film 发表于 2013-2-7 09:08:03

实现OS中BOOTLOADER过程,并进入保护模式的代码

<div class="highlighter">
[*];;;;;;;实现进入进入保护模式,简单实现gdt,还没实现idt,用fat格式,这样利于内核文件的扩展。编写好内核之后,
[*];;;;;;;;可以直接放到软盘的根目录下。不需要在用镜像文件写入磁盘。
[*];;;;;;;;内存分配,堆栈在8FFFF,内核在500H,目录文件名被读取到7E00,等待扩展保护模式中断,完善磁盘读文件过程
[*]
[*] ; 告诉编译器程序加载到7c00处
[*]<span />
[*]CATALOG equ 0x7E00          ;catalog loaded at 0x7e00
[*]KERNEL  equ 0x500           ;kernel.bin loaded at 0x500.
[*]jmp Start
[*]; 引导区文件系统数据
[*];----------------------------------------------------------------------------
[*]    brOEM       DB " T's OS "        ; 0003h - 引导程序的名字
[*]    brBPS       DW 0x200        ; 000Bh - 每扇区的字节数 512
[*]    brSPC       DB 0x01            ; 000Dh - 每簇扇区数
[*]    brResCount  DW    0x0001     ; 000Eh - 保留扇区数
[*]    brFATs      DB 0x02            ; 0010h - FAT 备份数
[*]    brRootEntries    DW    0x00e0     ; 0011h - 根目录文件数
[*]    brSectorCount    
[*]                DW 2880        ; 0013h - 磁盘容量扇区数< 32MB
[*]    brMedia     DB 240         ; 0015h - 媒体描述符
[*]    brSPF       DW 9           ; 0016h - 每FAT扇区数
[*]    brSPH       DW 18         ; 0018h - 每磁道扇区数
[*]    brHPC       DW 2           ; 001Ah - 盘面数
[*]    brHidden    DD 0            ; 001Ch - 隐藏扇区数
[*]    brSectors   DD 0           ; 0020h - 如果大于32m的扇区总数
[*]                DB 0           ; 0024h - 物理驱动器号
[*]                DB 0           ; 0025h - 系统保留
[*]                DB 29H         ; 0026h - 扩展扇区标记(包含29h)
[*]    brSerialNum DD    00000006H    ; 0027h - 卷ID
[*]    brLabel     DB    'NO NAME    '    ; 002Bh - 卷标
[*]    brFSID      DB    'FAT12   '        ; 0036h - 系统保留
[*];------------------------------------------------------------------------
[*]Start:
[*]mov ax, cs
[*]mov ds, ax
[*]mov es, ax
[*]mov ax,0x8000               ;栈放在0x1F00段里,这里栈有问题(栈放在0x1F00段里,会覆盖掉中断程序。)!!!!!!!!!!!!!!!
[*]mov ss,ax
[*]mov sp,0xffff               ; 堆栈入口 8FFFF
[*]call DispStr                ; 调用显示字符串例程
[*]call LoadFile               ; 把目录区读入到200的地方,bios
[*]call FindFile               ; 在7E00的地方找kernel.bin,读出来放到500的地方,并显示读取成功
[*]call Clrscr             ;先清屏
[*]<span />
[*];=============================================
[*];SwitchPro建立GDT,进入保护模式
[*];=============================================
[*]SwitchPro;
[*]    ; 打开A20
[*]    in al, 92h
[*]    or al, 00000010b
[*]    out 92h, al
[*]    ; end 打开A20
[*]    ; 设置GDT
[*]    cli
[*]    ;mov ax,KERNEL          ; lgdt 指令加载 gdtr 是以ds为数据段加载
[*]    ;mov ds,ax
[*]    ;lea si, 
[*]    lgdt 
[*]    ;lea si, 
[*]    ;lidt 
[*]<span />
[*]    mov eax, cr0
[*]    or eax,1
[*]    mov cr0, eax
[*]    jmp dword selcode:0         ;进入保护模式,并且跳到下面的段中
[*]    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;jmp KERNEL   保护模式下,跳到kenel.bin开始执行内核.等待内核编码完成在实现
[*]<span />
[*]
[*]CODE32:
[*]    sti
[*]    mov eax,codesel_gdt
[*]    mov ebx,datasel_gdt
[*]    mov ax,ProMessage
[*]    mov bp,ax
[*]    mov cx,ProMsglength
[*]    ;call   PrintMsg        ;保护模式中断有问题,需要修改这里,最好能利用实模式下的bios中断程序。
[*];===================
[*]mov ax,videosel ; 初始化gs,使其指向显示内存
[*]mov gs,ax 
[*]mov word ,0x741 ; 在保护模式下显示一个白色的字符A
[*];===================
[*]    jmp $           ; 到此停止!!!!!!!!!!!!!!!!!!!!!!!
[*]<span />
[*]
[*]<span />
[*];===================================================================
[*];初始化gdtr和gdt
[*];===================================================================
[*]<span />
[*]gdtr:
[*]    dw gdt_end - gdt-1              ; gdt的长度--16位(800H)GDT界限gdt limit=2048, 256 GDT entries
[*]                        ;这里应该是伪长度7,15,23,31,因为从0开始计算的
[*]    dd gdt                                      ; gdt的物理地址--32位GDT基地址
[*]                        ;0x00007c930017!!!!!!!!
[*]gdt:
[*]    gdt0:
[*]        dw 0,0,0,0                             ; 一定要为0
[*]codesel_gdt:
[*]    dw    0xffff                           ; 界限Limit值 = 0x100000 * 0x1000 = 4GB
[*]    dw    CODE32;0x0000                        ; 基地址 = CODE32.!!!!!!!是不是最好设置从0开始?
[*]    db    0x00
[*]    db    0x9A                             ; 表示 存在 可执行可读代码段
[*]    db    0xCF                             ; 粒度以及32位代码1100=0XC
[*]    db    0x00                             
[*]datasel_gdt:
[*]    dw    0xffff                           ; 界限4GB
[*]    dw    0x0000                           ; 基地址
[*]    db    0x00
[*]    db    0x92                             ; 表示 存在 可读写数据段
[*]    db    0xCF                             ; 粒度以及数据锻大小4G,1100=0XC
[*]    db    0x00                             
[*];========================
[*]videosel equ $-gdt 
[*]dw 3999 
[*]dw 0x8000 ; 基址是0xb8000
[*]db 0x0b
[*]db 0x92 
[*]db 0x00 
[*]db 0x00
[*];========================
[*]gdt_end:
[*]<span />
[*]selcode equ codesel_gdt - gdt           ;索引值1,2,3....
[*]seldata equ datasel_gdt - gdt
[*]<span />
[*]<span />
[*];=============================================
[*];DispStr 显示boot已经启动!
[*];=============================================
[*]DispStr:
[*]   mov ax, BootMessage
[*]   mov bp, ax ; es:bp = 串地址
[*]   mov cx, Msglength ; cx = 串长度
[*]   call PrintMsg
[*]ret
[*]<span />
[*];=============================================
[*];LoadFile 把目录从软盘中读出来!
[*];=============================================
[*]LoadFile:
[*]mov ax,19       ;开始的扇区
[*]mov bx,CATALOG          ;目录放在7E00H的地方!!!!!!!!!!!!!!!!!!!!!!!!!!!
[*]mov cx,14       ;目录扇区个数
[*]loopreadsec:
[*]push ax
[*]push bx
[*]push cx
[*]call    LBACHS          ; 调用转换
[*]mov     dl, 0           ; 因为是a:所以为0!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
[*]mov     ah, 0x02        ; BIOS 读取扇区命令
[*]mov     al, 0x01        ; 一个扇区
[*]<span />int     0x13            ; 调用中断
[*]nop
[*]pop cx
[*]pop bx
[*]pop ax
[*]add bx,200
[*]inc ax
[*]loop loopreadsec
[*]ret
[*];=============================================
[*]; 转换逻辑块访问为读取磁盘所使用的磁道,盘面,扇区
[*]; 相对扇区 = (逻辑扇区 / 每磁道扇区数) + 1
[*]; 相对盘面   = (逻辑扇区 / 每磁道扇区数) MOD 盘面数
[*]; 相对磁道 = 逻辑扇区 / (每磁道扇区数 * 盘面数)
[*];=============================================
[*]LBACHS:
[*]    xor     dx, dx              ; dx = 0
[*]    mov     cx,18
[*]    div     cx        ; div: ax/18 -> 商:ax 余数:dx
[*]    inc     dl        ;sec           ; 
[*]    mov     cl, dl    ;sector
[*]    xor     dx, dx    ; dx = 0
[*]    push    bx
[*]    mov     bx,2
[*]    div     bx        ; ax/2 -> 商:ax 余数:dx
[*]    pop     bx
[*]    mov     ch, al    ; track
[*]    mov     dh, dl    ; head
[*]ret
[*]<span />
[*];=============================================
[*];FindFile 查找文件名,并且装到0x500,显示Load Kernel.bin Success!
[*];=============================================
[*]FindFile:
[*]cld                             ;地址自动增加
[*]mov cx,224                          ;根目录共有224个文件
[*]mov di,CATALOG                          ;目录放在7E00H的地方!!!!!!!!!!!!!!!!!!!!!
[*].l_findfile:
[*]push cx
[*]lea si,                             ;?
[*]push di
[*]mov cx,11                           ;8+3=0xb文件名和后缀长度
[*]repe cmpsb            
[*]pop di
[*]je findfile_ok
[*]add di,32                           ;开始找下1个文件
[*]pop cx
[*]loop .l_findfile
[*]mov ax, LoadKerFail                     ;失败
[*]mov bp, ax                          ; es:bp = 串地址
[*]mov cx, LoadKerFaillength                   ; cx = 串长度
[*]call PrintMsg
[*]ret
[*]<span />
[*]findfile_ok:
[*]pop cx
[*]add di,26       ;取文件占用的第一个簇号,即起始簇
[*]mov ax,
[*]add ax,31       ;簇转成扇区
[*]mov bx,KERNEL                           ;文件放在0x500!!!!!!!!!!!!!!!!!!!!!!!!!!!
[*]call    LBACHS          ; 调用转换
[*]mov     dl, 0           ; 因为是a:所以为0!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
[*]mov     ah, 0x02        ; BIOS 读取扇区命令
[*]mov     al, 0x03                            ; 一个扇区,这里不应该只读一个扇区,应该根据文件大小来决定,等待修改!!!!!
[*]<span />int     0x13            ; 调用中断,内核放在0x1e00!      ;在磁盘的位置?
[*]mov ax, LoadKerSuess                        ;成功
[*]mov bp, ax                          ; es:bp = 串地址   
[*]mov cx, LoadKerlength                       ; cx = 串长度
[*]call PrintMsg   
[*]ret
[*]<span />
[*];=============================================
[*];清屏
[*];=============================================
[*]Clrscr :
[*]   mov ax,0x0600 ; 使用中断10h的功能6,实现卷屏,如果al=0则清屏
[*]   mov cx,0x0000 ; 清屏
[*]   mov dx,0x174f ; 卷屏至23,79
[*]   mov bh,0 ; 使用颜色0来填充
[*]   int 0x10 ; 调用10h中断
[*]ret
[*]<span />
[*];=============================================
[*];显示信息
[*];=============================================
[*]PrintMsg:
[*]   mov ax, 01301h ; ah = 13, al = 01h
[*]   mov bx, 000ch ; 页号为0(bh = 0) 黑底红字(bl = 0Ch,高亮)
[*]   mov dl, 0
[*]   mov dh, BYTE 
[*]   int 10h ; 10h 号中断
[*]   add dh,1
[*]   mov BYTE ,dh
[*]ret
[*]<span />
[*]BootMessage: db "Welcome to T's OS!",0x0D,0x0A
[*]Msglength equ $-BootMessage
[*]DB 0x00
[*]Kernel: db 'KERNEL  BIN'                    ;8+3=11位;将来这里改成内核的文件名!!!!!!!!!!!!!
[*]LoadKerSuess: db 'Load Kernel.bin Success!',0x0D,0x0A
[*]LoadKerlength equ $-LoadKerSuess
[*]DB 0x00
[*]LoadKerFail: db 'Load Kernel.bin Fail!',0x0D,0x0A
[*]LoadKerFaillength equ $-LoadKerFail
[*]DB 0x00
[*]ProMessage: db "I'm in the Pro Mode!",0x0D,0x0A
[*]ProMsglength equ $-ProMessage
[*]DB 0x00
[*]NoLine DB 0x00
[*]times 510-($-$$) db 0 ; 填充剩下的空间,使生成的二进制代码恰好为512字节
[*]<span />
[*]dw 0xaa55 ; 结束标志
[*]<span />
[*];把这段代码用NASM编译一下:
[*];nasm boot.asm –o boot.bin
[*];应该把内核在pro模式下加载就对了!
页: [1]
查看完整版本: 实现OS中BOOTLOADER过程,并进入保护模式的代码