• 40 操作系统-从bootloader到内核雏形


    参考

    https://blog.51cto.com/13475106/category6.html及狄泰软件相关课程

    一.整体的设计

    操作系统-从bootloader到内核雏形
    从上图可以得到一个问题,为什么不能从boot直接加载kernnel,并跳转运行?
    该设计的思路
    1.boot必须小于512字节,无法完成过多功能
    2.kernel需要运行于32位保护模式(汇编+c语言)
    3.使用loader中转:获取必要硬件信息,进入保护模式
    进行的重构方案如下所示
    操作系统-从bootloader到内核雏形
    文件功能的定义
    common.asm--常量定义,宏定义
    blfunc.asm--实模式下的文件加载功能定义
    boot.asm--加载loader并跳转[引导扇区]
    loader.asm--在这里需要进行的操作是必要硬件初始化,加载kernel,进入保护模式,跳转到kernel执行

    需要进行的修改
    1.将之前定义的inc.asm修改成common.asm,并在makefile中的链接关系将其相关的名字进行修改
    2.在loader.asm中相关的头文件进行修改
    3.函数重构的实现--将其实现不同的接口[将之前的代码进行改写,细分模块
    操作系统-从bootloader到内核雏形
    blfunc.asm注意事项
    1.%include "blfunc.asm"必须是第一条"包含"语句
    2.%include "blfunc.asm"强制从BLMain标签处开始执行
    3.Buffer为必要的内存缓冲区必须在代码末尾定义

    内核雏形构造
    操作系统-从bootloader到内核雏形
    通过上图可知,kernel.out加载进内存后不能直接被x86处理器运行,产生的原因有三种
    1.kernel.out是Linux系统中的可执行程序
    2.Linux中的可执行程序为elf格式的文件-固定数据格式
    3.处理器只认代码和数据,无法正确执行elf可执行程序
    改进方法
    1.提取elf文件中的代码段与数据段-删除elf文件格式信息
    2.重定位提取后的代码和数据段,得到内核文件
    3.加载内核文到内存-起始地址可自定义
    4.跳转到内核入口地址处执行

    在这里介绍一个工具,会有三种数据处理格式-如下图所示
    操作系统-从bootloader到内核雏形
    操作系统-从bootloader到内核雏形
    所需的实验文件链接https://down.51cto.com/data/2468702
    小结
    1.实验nasm和gcc编译得到的是elf目标文件
    2.ld将elf目标文件装配成为elf可执行程序
    3.实验elf2kobj将可执行程序转换为内核文件
    4.在实模式下加载转换得到的内核文件
    5.进入保护模式后执行跳转内核起始位置处执行

    参考代码分别如下:

    bochsrc

    ###############################################################
    # Configuration file for Bochs
    ###############################################################
    
    # how much memory the emulated machine will have
    megs: 32
    
    # filename of ROM images
    romimage: file=/usr/local/share/bochs/BIOS-bochs-latest
    vgaromimage: file=/usr/share/vgabios/vgabios.bin
    
    # what disk images will be used
    # floppya: 1_44=freedos.img, status=inserted
    floppya: 1_44=D.T.OS, status=inserted
    
    # choose the boot disk.
    boot: a
    
    # where do we send log messages?
    # log: bochsout.txt
    
    # disable the mouse
    mouse: enabled=0
    
    # enable key mapping, using US layout as default.
    keyboard_mapping: enabled=1, map=/usr/local/share/bochs/keymaps/x11-pc-us.map
    

     

    common.asm

    ; PIC-8259A Ports 
    MASTER_ICW1_PORT                        equ     0x20
    MASTER_ICW2_PORT                        equ     0x21
    MASTER_ICW3_PORT                        equ     0x21
    MASTER_ICW4_PORT                        equ     0x21
    MASTER_OCW1_PORT                        equ     0x21
    MASTER_OCW2_PORT                        equ     0x20
    MASTER_OCW3_PORT                        equ     0x20
    
    SLAVE_ICW1_PORT                         equ     0xA0
    SLAVE_ICW2_PORT                         equ     0xA1
    SLAVE_ICW3_PORT                         equ     0xA1
    SLAVE_ICW4_PORT                         equ     0xA1
    SLAVE_OCW1_PORT                         equ     0xA1
    SLAVE_OCW2_PORT                         equ     0xA0
    SLAVE_OCW3_PORT                         equ     0xA0
    
    MASTER_EOI_PORT                         equ     0x20
    MASTER_IMR_PORT                         equ     0x21
    MASTER_IRR_PORT                         equ     0x20
    MASTER_ISR_PORT                         equ     0x20
    
    SLAVE_EOI_PORT                          equ     0xA0
    SLAVE_IMR_PORT                          equ     0xA1
    SLAVE_IRR_PORT                          equ     0xA0
    SLAVE_ISR_PORT                          equ     0xA0
    
    ; Segment Attribute
    DA_32       equ    0x4000
    DA_LIMIT_4K    EQU       0x8000
    DA_DR       equ    0x90
    DA_DRW      equ    0x92
    DA_DRWA     equ    0x93
    DA_C        equ    0x98
    DA_CR       equ    0x9A
    DA_CCO      equ    0x9C
    DA_CCOR     equ    0x9E
    
    ; Segment Privilege
    DA_DPL0        equ      0x00    ; DPL = 0
    DA_DPL1        equ      0x20    ; DPL = 1
    DA_DPL2        equ      0x40    ; DPL = 2
    DA_DPL3        equ      0x60    ; DPL = 3
    
    ; Special Attribute
    DA_LDT       equ    0x82
    DA_TaskGate  equ    0x85    ; 任务门类型值
    DA_386TSS    equ    0x89    ; 可用 386 任务状态段类型值
    DA_386CGate  equ    0x8C    ; 386 调用门类型值
    DA_386IGate  equ    0x8E    ; 386 中断门类型值
    DA_386TGate  equ    0x8F    ; 386 陷阱门类型值
    
    ; Selector Attribute
    SA_RPL0    equ    0
    SA_RPL1    equ    1
    SA_RPL2    equ    2
    SA_RPL3    equ    3
    
    SA_TIG    equ    0
    SA_TIL    equ    4
    
    PG_P    equ    1    ; 页存在属性位
    PG_RWR  equ    0    ; R/W 属性位值, 读/执行
    PG_RWW  equ    2    ; R/W 属性位值, 读/写/执行
    PG_USS  equ    0    ; U/S 属性位值, 系统级
    PG_USU  equ    4    ; U/S 属性位值, 用户级
    
    ; 描述符
    ; usage: Descriptor Base, Limit, Attr
    ;        Base:  dd
    ;        Limit: dd (low 20 bits available)
    ;        Attr:  dw (lower 4 bits of higher byte are always 0)
    %macro Descriptor 3                              ; 段基址, 段界限, 段属性
        dw    %2 & 0xFFFF                         ; 段界限1
        dw    %1 & 0xFFFF                         ; 段基址1
        db    (%1 >> 16) & 0xFF                   ; 段基址2
        dw    ((%2 >> 8) & 0xF00) | (%3 & 0xF0FF) ; 属性1 + 段界限2 + 属性2
        db    (%1 >> 24) & 0xFF                   ; 段基址3
    %endmacro                                     ; 共 8 字节
    
    ; 门
    ; usage: Gate Selector, Offset, DCount, Attr
    ;        Selector:  dw
    ;        Offset:    dd
    ;        DCount:    db
    ;        Attr:      db
    %macro Gate 4
        dw    (%2 & 0xFFFF)                      ; 偏移地址1
        dw    %1                                 ; 选择子
        dw    (%3 & 0x1F) | ((%4 << 8) & 0xFF00) ; 属性
        dw    ((%2 >> 16) & 0xFFFF)              ; 偏移地址2
    %endmacro 
    

      

    blfunc.asm

    jmp short _start
    nop
    
    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   "
        
    const:
        RootEntryOffset  equ 19
        RootEntryLength  equ 14
        SPInitValue      equ BaseOfStack - EntryItemLength
        EntryItem        equ SPInitValue
        EntryItemLength  equ 32
        FatEntryOffset   equ 1
        FatEntryLength   equ 9
        
    _start:
        jmp BLMain
        
    ;
    ; return:
    ;     dx --> (dx != 0) ? success : failure
    LoadTarget:
    	mov ax, RootEntryOffset
    	mov cx, RootEntryLength
    	mov bx, Buffer
    	
    	call ReadSector
    	
    	mov si, Target
    	mov cx, TarLen
    	mov dx, 0
    	
    	call FindEntry
    	
    	cmp dx, 0
    	jz finish
    	
    	mov si, bx
    	mov di, EntryItem
    	mov cx, EntryItemLength
    	
    	call MemCpy
    	
    	mov ax, FatEntryLength
    	mov cx, [BPB_BytsPerSec]
    	mul cx
    	mov bx, BaseOfTarget
    	sub bx, ax
    	
    	mov ax, FatEntryOffset
    	mov cx, FatEntryLength
    	
    	call ReadSector
    	
    	mov dx, [EntryItem + 0x1A]
    	mov si, BaseOfTarget / 0x10
    	mov es, si
    	mov si, 0
    	
    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 finish
        add si, 512
        cmp si, 0
        jnz continue
        mov si, es
        add si, 0x1000
        mov es, si
        mov si, 0
    continue:
        jmp loading
     
    finish:   
        ret
    
    ; cx --> index
    ; bx --> fat table address
    ;
    ; return:
    ;     dx --> fat[index]
    FatVec:
        push cx
        
        mov ax, cx
        shr ax, 1
        
        mov cx, 3
        mul cx
        mov cx, ax
        
        pop ax
        
        and ax, 1
        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:
        push ax
        mov ah, 0x00
        mov dl, [BS_DrvNum]
        int 0x13
        pop ax
        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
    

      

    boot.asm

    BaseOfBoot    equ    0x7C00
    
    org BaseOfBoot
    
    %include "blfunc.asm"
    
    interface:
        BaseOfStack    equ    BaseOfBoot
        BaseOfTarget   equ    0x9000
        Target db  "LOADER     "
        TarLen equ ($-Target)
    
    BLMain:
        mov ax, cs
    	mov ss, ax
    	mov ds, ax
    	mov es, ax
    	mov sp, SPInitValue
    	
    	call LoadTarget
    	
    	cmp dx, 0
    	jz output
    	jmp BaseOfTarget
    	
    output:	
        mov bp, ErrStr
        mov cx, ErrLen
    	call Print
    	
    	jmp $	
    
    ErrStr db  "No LOADER"	
    ErrLen equ ($-ErrStr)
    
    Buffer:
    	times 510-($-$$) db 0x00
    	db 0x55, 0xaa
    

      

    loader.asm

    BaseOfLoader   equ   0x9000
    
    org BaseOfLoader
    
    %include "blfunc.asm"
    %include "common.asm"
    
    interface:
        BaseOfStack    equ    BaseOfLoader
        BaseOfTarget   equ    0xB000
        Target db  "KERNEL     "
        TarLen equ ($-Target)
    
    [section .gdt]
    ; GDT definition
    ;                                       Base,         Limit,        Attribute
    GDT_ENTRY            :     Descriptor    0,            0,           0
    CODE32_FLAT_DESC     :     Descriptor    0,         0xFFFFF,        DA_C + DA_32
    CODE32_DESC          :     Descriptor    0,    Code32SegLen - 1,    DA_C + DA_32
    ; GDT end
    
    GdtLen    equ   $ - GDT_ENTRY
    
    GdtPtr:
              dw   GdtLen - 1
              dd   0
              
              
    ; GDT Selector
    Code32FlatSelector    equ (0x0001 << 3) + SA_TIG + SA_RPL0
    Code32Selector        equ (0x0002 << 3) + SA_TIG + SA_RPL0
    
    
    ; end of [section .gdt]
    
    
    [section .s16]
    [bits 16]
    BLMain:
        mov ax, cs
        mov ds, ax
        mov es, ax
        mov ss, ax
        mov sp, SPInitValue
        
        ; initialize GDT for 32 bits code segment
        mov esi, CODE32_SEGMENT
        mov edi, CODE32_DESC
        
        call InitDescItem
        
        ; initialize GDT pointer struct
        mov eax, 0
        mov ax, ds
        shl eax, 4
        add eax, GDT_ENTRY
        mov dword [GdtPtr + 2], eax
        
        call LoadTarget
    	
    	cmp dx, 0
    	jz output
    
        ; 1. load GDT
        lgdt [GdtPtr]
        
        ; 2. close interrupt
        ;    set IOPL to 3
        cli 
        
        pushf
        pop eax
        
        or eax, 0x3000
        
        push eax
        popf
        
        ; 3. open A20
        in al, 0x92
        or al, 00000010b
        out 0x92, al
        
        ; 4. enter protect mode
        mov eax, cr0
        or eax, 0x01
        mov cr0, eax
        
        ; 5. jump to 32 bits code
        jmp dword Code32Selector : 0
    
    output:	
        mov bp, ErrStr
        mov cx, ErrLen
    	call Print
    	
    	jmp $
    
    ; esi    --> code segment label
    ; edi    --> descriptor label
    InitDescItem:
        push eax
    
        mov eax, 0
        mov ax, cs
        shl eax, 4
        add eax, esi
        mov word [edi + 2], ax
        shr eax, 16
        mov byte [edi + 4], al
        mov byte [edi + 7], ah
        
        pop eax
        
        ret
        
        
    [section .s32]
    [bits 32]
    CODE32_SEGMENT:
        jmp dword Code32FlatSelector : BaseOfTarget
    
    Code32SegLen    equ    $ - CODE32_SEGMENT
    
    ErrStr db  "No KERNEL"	
    ErrLen equ ($-ErrStr)
    
    Buffer db  0
    

      

    kentry.asm

    global _start
    
    extern KMain
    
    [section .text]
    [bits 32]
    _start:
        mov ebp, 0
        
        call KMain
        
        jmp $
    

    kmain.c

    #include "kernel.h"
    
    void KMain()
    {
    
    }
    

    kernel.h暂时为空文件,无内容

    makefile修改为:

    .PHONY : all clean rebuild
    
    KERNEL_ADDR := B000
    IMG := D.T.OS
    IMG_PATH := /mnt/hgfs
    
    DIR_DEPS := deps
    DIR_EXES := exes
    DIR_OBJS := objs
    
    DIRS := $(DIR_DEPS) $(DIR_EXES) $(DIR_OBJS)
    
    KENTRY_SRC := kentry.asm
    BLFUNC_SRC := blfunc.asm
    BOOT_SRC   := boot.asm
    LOADER_SRC := loader.asm
    COMMON_SRC := common.asm
    
    KERNEL_SRC := kmain.c
    
    BOOT_OUT   := boot
    LOADER_OUT := loader
    KERNEL_OUT := kernel
    KENTRY_OUT := $(DIR_OBJS)/kentry.o
    
    EXE := kernel.out
    EXE := $(addprefix $(DIR_EXES)/, $(EXE))
    
    SRCS := $(wildcard *.c)
    OBJS := $(SRCS:.c=.o)
    OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
    DEPS := $(SRCS:.c=.dep)
    DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))
    
    all : $(DIR_OBJS) $(DIR_EXES) $(IMG) $(BOOT_OUT) $(LOADER_OUT) $(KERNEL_OUT)
    	@echo "Build Success ==> D.T.OS!"
    	
    ifeq ("$(MAKECMDGOALS)", "all")
    -include $(DEPS)
    endif
    
    ifeq ("$(MAKECMDGOALS)", "")
    -include $(DEPS)
    endif
    
    $(IMG) :
    	bximage $@ -q -fd -size=1.44
    	
    $(BOOT_OUT) : $(BOOT_SRC) $(BLFUNC_SRC)
    	nasm $< -o $@
    	dd if=$@ of=$(IMG) bs=512 count=1 conv=notrunc
    	
    $(LOADER_OUT) : $(LOADER_SRC) $(COMMON_SRC) $(BLFUNC_SRC)
    	nasm $< -o $@
    	sudo mount -o loop $(IMG) $(IMG_PATH)
    	sudo cp $@ $(IMG_PATH)/$@
    	sudo umount $(IMG_PATH)
    	
    $(KENTRY_OUT) : $(KENTRY_SRC) $(COMMON_SRC)
    	nasm -f elf $< -o $@
        
    $(KERNEL_OUT) : $(EXE)
    	./elf2kobj -c$(KERNEL_ADDR) $< $@
    	sudo mount -o loop $(IMG) $(IMG_PATH)
    	sudo cp $@ $(IMG_PATH)/$@
    	sudo umount $(IMG_PATH)
    	
    $(EXE) : $(KENTRY_OUT) $(OBJS)
    	ld -s $^ -o $@
    	
    $(DIR_OBJS)/%.o : %.c
    	gcc -fno-builtin -fno-stack-protector -o $@ -c $(filter %.c, $^)
    
    $(DIRS) :
    	mkdir $@
    
    ifeq ("$(wildcard $(DIR_DEPS))", "")
    $(DIR_DEPS)/%.dep : $(DIR_DEPS) %.c
    else
    $(DIR_DEPS)/%.dep : %.c
    endif
    	@echo "Creating $@ ..."
    	@set -e; 
    	gcc -MM -E $(filter %.c, $^) | sed 's,(.*).o[ :]*,objs/1.o $@ : ,g' > $@
    	
    clean :
    	rm -fr $(IMG) $(BOOT_OUT) $(LOADER_OUT) $(KERNEL_OUT) $(DIRS)
    	
    rebuild :
    	@$(MAKE) clean
    	@$(MAKE) all
    

      

      

      

     

  • 相关阅读:
    asp.net项目发布网上-当前自定义错误设置禁止远程查看应用程序
    TortoiseSVN提交文件的时候卡死
    TortoiseSVN,排除不想提交文件的方法(转)
    VS2010 发布网站时文件丢失
    SQL SERVER2012秘钥
    QTP常用功能
    XAMPP和Bugfree详细教程
    模块
    匿名函数、函数递归与二分法、面向过程
    迭代器、生成式、生成器
  • 原文地址:https://www.cnblogs.com/lh03061238/p/14616544.html
Copyright © 2020-2023  润新知