Chinaunix首页 | 论坛 | 博客
  • 博客访问: 469940
  • 博文数量: 164
  • 博客积分: 4024
  • 博客等级: 上校
  • 技术积分: 1580
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-10 16:27
文章分类

全部博文(164)

文章存档

2011年(1)

2010年(108)

2009年(55)

我的朋友

分类:

2010-06-25 09:29:49

loader完成了加载内核入内存,该完成跳入保护模式了。进保护模式也是很关键的一步了,保护模式的知识真的要好好看看。俺不知道俺现在是不是真的理解了,马马虎虎。代码书上也讲的很详细,我这里就抄一下吧。
kernel还是用上阶段的,对loader的修改:主要是增加了GDT 分页机制 为了分页获取内存信息
; GDT ------------------------------------------------------------------------------------------------------------------------------------------------------------
;                                                段基址            段界限     , 属性
LABEL_GDT:   Descriptor             0,                    0, 0      ; 空描述符
LABEL_DESC_FLAT_C:  Descriptor             0,              0fffffh, DA_CR  | DA_32 | DA_LIMIT_4K   ; 0 ~ 4G
LABEL_DESC_FLAT_RW:  Descriptor             0,              0fffffh, DA_DRW | DA_32 | DA_LIMIT_4K   ; 0 ~ 4G
LABEL_DESC_VIDEO:  Descriptor  0B8000h,               0ffffh, DA_DRW                         | DA_DPL3 ; 显存首地址
; GDT ------------------------------------------------------------------------------------------------------------------------------------------------------------
GdtLen  equ $ - LABEL_GDT
GdtPtr  dw GdtLen - 1    ; 段界限
  dd BaseOfLoaderPhyAddr + LABEL_GDT  ; 基地址
; GDT 选择子 ----------------------------------------------------------------------------------
SelectorFlatC  equ LABEL_DESC_FLAT_C - LABEL_GDT
SelectorFlatRW  equ LABEL_DESC_FLAT_RW - LABEL_GDT
SelectorVideo  equ LABEL_DESC_VIDEO - LABEL_GDT + SA_RPL3
; GDT 选择子 ----------------------------------------------------------------------------------
一些宏定义把他们整到了一个文件中,load.inc

 



BaseOfLoader        equ     09000h    ; LOADER.BIN 被加载到的位置 ---- 段地址
OffsetOfLoader        equ     0100h    ; LOADER.BIN 被加载到的位置 ---- 偏移地址

BaseOfLoaderPhyAddr    equ    BaseOfLoader * 10h    ; LOADER.BIN 被加载到的位置 ---- 物理地址 (= BaseOfLoader * 10h)


BaseOfKernelFile    equ     08000h    ; KERNEL.BIN 被加载到的位置 ---- 段地址
OffsetOfKernelFile    equ     0h    ; KERNEL.BIN 被加载到的位置 ---- 偏移地址


进入保护模式的代码:

 

LABEL_FILE_LOADED:

    call    KillMotor        ; 关闭软驱马达

    mov    dh, 1            ; "Ready."
    call    DispStrRealMode        ; 显示字符串
    
; 下面准备跳入保护模式 -------------------------------------------

; 加载 GDTR
    lgdt    [GdtPtr]

; 关中断
    cli

; 打开地址线A20
    in    al, 92h
    or    al, 00000010b
    out    92h, al

; 准备切换到保护模式
    mov    eax, cr0
    or    eax, 1
    mov    cr0, eax

; 真正进入保护模式
    jmp    dword SelectorFlatC:(BaseOfLoaderPhyAddr+LABEL_PM_START)

32位代码段:就是进到保护模式后显示各P


 

从此以后的代码在保护模式下执行 ----------------------------------------------------
; 32 位代码段. 由实模式跳入 ---------------------------------------------------------
[SECTION .s32]

ALIGN    32

[BITS    32]

LABEL_PM_START:
    mov    ax, SelectorVideo
    mov    gs, ax
    mov    ax, SelectorFlatRW
    mov    ds, ax
    mov    es, ax
    mov    fs, ax
    mov    ss, ax
    mov    esp, TopOfStack

    push    szMemChkTitle
    call    DispStr
    add    esp, 4

    call    DispMemInfo
    call    SetupPaging

    mov    ah, 0Fh                ; 0000: 黑底 1111: 白字
    mov    al, 'P'
    mov    [gs:((80 * 0 + 39) * 2)], ax    ; 屏幕第 0 行, 第 39 列。
    jmp    $


加入分页机制:首先要得到内存信息,以便确定页表个数

得到内存信息:

    ; 得到内存数
    mov    ebx, 0            ; ebx = 后续值, 开始时需为 0
    mov    di, _MemChkBuf        ; es:di 指向一个地址范围描述符结构(Address Range Descriptor Structure)
.MemChkLoop:
    mov    eax, 0E820h        ; eax = 0000E820h
    mov    ecx, 20            ; ecx = 地址范围描述符结构的大小
    mov    edx, 0534D4150h        ; edx = 'SMAP'
    int    15h            ; int 15h
    jc    .MemChkFail
    add    di, 20
    inc    dword [_dwMCRNumber]    ; dwMCRNumber = ARDS 的个数
    cmp    ebx, 0
    jne    .MemChkLoop
    jmp    .MemChkOK
.MemChkFail:
    mov    dword [_dwMCRNumber], 0
.MemChkOK:

显示内存信息:

显示内存信息 --------------------------------------------------------------
DispMemInfo:
    push    esi
    push    edi
    push    ecx

    mov    esi, MemChkBuf
    mov    ecx, [dwMCRNumber]    ;for(int i=0;i<[MCRNumber];i++) // 每次得到一个ARDS(Address Range Descriptor Structure)结构
.loop:                    ;{
    mov    edx, 5            ;    for(int j=0;j<5;j++)    // 每次得到一个ARDS中的成员,共5个成员
    mov    edi, ARDStruct        ;    {            // 依次显示:BaseAddrLow,BaseAddrHigh,LengthLow,LengthHigh,Type
.1:                    ;
    push    dword [esi]        ;
    call    DispInt            ;        DispInt(MemChkBuf[j*4]); // 显示一个成员
    pop    eax            ;
    stosd                ;        ARDStruct[j*4] = MemChkBuf[j*4];
    add    esi, 4            ;
    dec    edx            ;
    cmp    edx, 0            ;
    jnz    .1            ;    }
    call    DispReturn        ;    printf("\n");
    cmp    dword [dwType], 1    ;    if(Type == AddressRangeMemory) // AddressRangeMemory : 1, AddressRangeReserved : 2
    jne    .2            ;    {
    mov    eax, [dwBaseAddrLow]    ;
    add    eax, [dwLengthLow]    ;
    cmp    eax, [dwMemSize]    ;        if(BaseAddrLow + LengthLow > MemSize)
    jb    .2            ;
    mov    [dwMemSize], eax    ;            MemSize = BaseAddrLow + LengthLow;
.2:                    ;    }
    loop    .loop            ;}
                    ;
    call    DispReturn        ;printf("\n");
    push    szRAMSize        ;
    call    DispStr            ;printf("RAM size:");
    add    esp, 4            ;
                    ;
    push    dword [dwMemSize]    ;
    call    DispInt            ;DispInt(MemSize);
    add    esp, 4            ;

    pop    ecx
    pop    edi
    pop    esi
    ret
; ---------------------------------------------------

下面就启动分页机制了:

 


 

启动分页机制 --------------------------------------------------------------
SetupPaging:
    ; 根据内存大小计算应初始化多少PDE以及多少页表
    xor    edx, edx
    mov    eax, [dwMemSize]
    mov    ebx, 400000h    ; 400000h = 4M = 4096 * 1024, 一个页表对应的内存大小
    div    ebx
    mov    ecx, eax    ; 此时 ecx 为页表的个数,也即 PDE 应该的个数
    test    edx, edx
    jz    .no_remainder
    inc    ecx        ; 如果余数不为 0 就需增加一个页表
.no_remainder:
    push    ecx        ; 暂存页表个数

    ; 为简化处理, 所有线性地址对应相等的物理地址. 并且不考虑内存空洞.

    ; 首先初始化页目录
    mov    ax, SelectorFlatRW
    mov    es, ax
    mov    edi, PageDirBase    ; 此段首地址为 PageDirBase
    xor    eax, eax
    mov    eax, PageTblBase | PG_P | PG_USU | PG_RWW
.1:
    stosd
    add    eax, 4096        ; 为了简化, 所有页表在内存中是连续的.
    loop    .1

    ; 再初始化所有页表
    pop    eax            ; 页表个数
    mov    ebx, 1024        ; 每个页表 1024 个 PTE
    mul    ebx
    mov    ecx, eax        ; PTE个数 = 页表个数 * 1024
    mov    edi, PageTblBase    ; 此段首地址为 PageTblBase
    xor    eax, eax
    mov    eax, PG_P | PG_USU | PG_RWW
.2:
    stosd
    add    eax, 4096        ; 每一页指向 4K 的空间
    loop    .2

    mov    eax, PageDirBase
    mov    cr3, eax
    mov    eax, cr0
    or    eax, 80000000h
    mov    cr0, eax
    jmp    short .3
.3:
    nop

    ret
; 分页机制启动完毕 ----------------------------------------------------------


一些符号的定义:

SECTION .data1 之开始 ---------------------------------------------------------------------------------------------
[SECTION .data1]

ALIGN    32

LABEL_DATA:
; 实模式下使用这些符号
; 字符串
_szMemChkTitle:            db    "BaseAddrL BaseAddrH LengthLow LengthHigh Type", 0Ah, 0
_szRAMSize:            db    "RAM size:", 0
_szReturn:            db    0Ah, 0
;; 变量
_dwMCRNumber:            dd    0    ; Memory Check Result
_dwDispPos:            dd    (80 * 6 + 0) * 2    ; 屏幕第 6 行, 第 0 列。
_dwMemSize:            dd    0
_ARDStruct:            ; Address Range Descriptor Structure
    _dwBaseAddrLow:        dd    0
    _dwBaseAddrHigh:    dd    0
    _dwLengthLow:        dd    0
    _dwLengthHigh:        dd    0
    _dwType:        dd    0
_MemChkBuf:    times    256    db    0
;
;; 保护模式下使用这些符号
szMemChkTitle        equ    BaseOfLoaderPhyAddr + _szMemChkTitle
szRAMSize        equ    BaseOfLoaderPhyAddr + _szRAMSize
szReturn        equ    BaseOfLoaderPhyAddr + _szReturn
dwDispPos        equ    BaseOfLoaderPhyAddr + _dwDispPos
dwMemSize        equ    BaseOfLoaderPhyAddr + _dwMemSize
dwMCRNumber        equ    BaseOfLoaderPhyAddr + _dwMCRNumber
ARDStruct        equ    BaseOfLoaderPhyAddr + _ARDStruct
    dwBaseAddrLow    equ    BaseOfLoaderPhyAddr + _dwBaseAddrLow
    dwBaseAddrHigh    equ    BaseOfLoaderPhyAddr + _dwBaseAddrHigh
    dwLengthLow    equ    BaseOfLoaderPhyAddr + _dwLengthLow
    dwLengthHigh    equ    BaseOfLoaderPhyAddr + _dwLengthHigh
    dwType        equ    BaseOfLoaderPhyAddr + _dwType
MemChkBuf        equ    BaseOfLoaderPhyAddr + _MemChkBuf


; 堆栈就在数据段的末尾
StackSpace:    times    1000h    db    0
TopOfStack    equ    BaseOfLoaderPhyAddr + $    ; 栈顶
; SECTION .data1 之结束


接下来就要调用他们了,显示内存信息并启动分页。

push szMemChkTitle

call DispStr

add esp,4

 

call DispMemInfo

call SetupPaging

 

loader.asm完成了,nasm loader.asm -o loader.bin得到loader.bin.其余文件和上阶段一样。

一些显示函数在lib.inc中


; ------------------------------------------------------------------------
; 显示 AL 中的数字
; ------------------------------------------------------------------------
DispAL:
    push    ecx
    push    edx
    push    edi

    mov    edi, [dwDispPos]

    mov    ah, 0Fh            ; 0000b: 黑底 1111b: 白字
    mov    dl, al
    shr    al, 4
    mov    ecx, 2
.begin:
    and    al, 01111b
    cmp    al, 9
    ja    .1
    add    al, '0'
    jmp    .2
.1:
    sub    al, 0Ah
    add    al, 'A'
.2:
    mov    [gs:edi], ax
    add    edi, 2

    mov    al, dl
    loop    .begin
    ;add    edi, 2

    mov    [dwDispPos], edi

    pop    edi
    pop    edx
    pop    ecx

    ret
; DispAL 结束-------------------------------------------------------------


; ------------------------------------------------------------------------
; 显示一个整形数
; ------------------------------------------------------------------------
DispInt:
    mov    eax, [esp + 4]
    shr    eax, 24
    call    DispAL

    mov    eax, [esp + 4]
    shr    eax, 16
    call    DispAL

    mov    eax, [esp + 4]
    shr    eax, 8
    call    DispAL

    mov    eax, [esp + 4]
    call    DispAL

    mov    ah, 07h            ; 0000b: 黑底 0111b: 灰字
    mov    al, 'h'
    push    edi
    mov    edi, [dwDispPos]
    mov    [gs:edi], ax
    add    edi, 4
    mov    [dwDispPos], edi
    pop    edi

    ret
; DispInt 结束------------------------------------------------------------

; ------------------------------------------------------------------------
; 显示一个字符串
; ------------------------------------------------------------------------
DispStr:
    push    ebp
    mov    ebp, esp
    push    ebx
    push    esi
    push    edi

    mov    esi, [ebp + 8]    ; pszInfo
    mov    edi, [dwDispPos]
    mov    ah, 0Fh
.1:
    lodsb
    test    al, al
    jz    .2
    cmp    al, 0Ah    ; 是回车吗?
    jnz    .3
    push    eax
    mov    eax, edi
    mov    bl, 160
    div    bl
    and    eax, 0FFh
    inc    eax
    mov    bl, 160
    mul    bl
    mov    edi, eax
    pop    eax
    jmp    .1
.3:
    mov    [gs:edi], ax
    add    edi, 2
    jmp    .1

.2:
    mov    [dwDispPos], edi

    pop    edi
    pop    esi
    pop    ebx
    pop    ebp
    ret
; DispStr 结束------------------------------------------------------------

; ------------------------------------------------------------------------
; 换行
; ------------------------------------------------------------------------
DispReturn:
    push    szReturn
    call    DispStr            ;printf("\n");
    add    esp, 4

    ret
; DispReturn 结束---------------------------------------------------------


; ------------------------------------------------------------------------
; 内存拷贝,仿 memcpy
; ------------------------------------------------------------------------
; void* MemCpy(void* es:pDest, void* ds:pSrc, int iSize);
; ------------------------------------------------------------------------
MemCpy:
    push    ebp
    mov    ebp, esp

    push    esi
    push    edi
    push    ecx

    mov    edi, [ebp + 8]    ; Destination
    mov    esi, [ebp + 12]    ; Source
    mov    ecx, [ebp + 16]    ; Counter
.1:
    cmp    ecx, 0        ; 判断计数器
    jz    .2        ; 计数器为零时跳出

    mov    al, [ds:esi]        ;
    inc    esi            ;
                    ; ┣ 逐字节移动
    mov    byte [es:edi], al    ;
    inc    edi            ;

    dec    ecx        ; 计数器减一
    jmp    .1        ; 循环
.2:
    mov    eax, [ebp + 8]    ; 返回值

    pop    ecx
    pop    edi
    pop    esi
    mov    esp, ebp
    pop    ebp

    ret            ; 函数结束,返回
; MemCpy 结束-------------------------------------------------------------

文件: MyOS4.rar
大小: 18KB
下载: 下载

阅读(1344) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~