操作系统的引导(三)

来源:互联网 发布:淘宝的人工服务怎么找 编辑:程序博客网 时间:2024/05/05 10:44

再学习了前面那些背景知识后,我们可以继续引导操作系统了。

 

在《操作系统的引导(二)》一篇中,我们已经通过分区引导程序将文件系统中的引导程序RMOSLDR加载到了内存5000:7C00的地方。现在我们来编写RMOSLDR把操作系统的内核从硬盘加载到内存中。RMOSLDR有两部分,第一部分是实模式汇编语言的部分,而第二部分则是C++的代码。这一节中我们先来编写汇编语言的部分

 


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;  This file is the first part of the RMOSLDR. The mission of this program is
;;  To create the running environment of the 2nd part of RMOSLDR which is a 32-
;;  bit c++ program. A stack, a flat protected memory model is needed.
;; 
;;  Remember that in bootstrap, RMOSLDR has been loaded to 0x5000:7c00. Memory
;;  Address space 5000:0000 - 5000:FFFF is reserved for this file. And the C++
;;  part starts from 6000:0000.
;;
;;  This program will do the following things:
;;  1: Get the total size of the memory. We won't be able to do so later in
;;     protected mode
;;
;;  2: Setup the GDT. we need a Kernel CS, a Kernel DS, and a Kernel FS. This
;;     GDT is temperory for the RMOSLDR. The kernel will re-initialize the virtual
;;     Memory
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 

先定义一些常数

;;;;;;;;;;;;;;;;;;;;
; Constants

MemTable                EQU     1000h       ; Pointer of the memory layout info

AddressRangeMemory      EQU     01          ; Memory available
AddressRangeReserved    EQU     02          ; Memory reserved



;;;;;;;;;;;;;;;;;;;;
; Directives

.model tiny
.686p

;;;;;;;;;;;;;;;;;;;;
; Begin Code segment

依然是16位模式,并且偏移地址是7C00
_TEXT SEGMENT use16 ; 16-bit code segment
.code
ORG     7c00h                          ; BootStrap puts us at 5000h:7c00

 

第一步:初始化各个段寄存器,并把堆栈建立在4000:FFF0处

start:

    ; Set the segment registers
    mov    ax, 5000h
    mov    ds, ax;
    mov    es, ax;
    mov    ax, 4000h
    mov    ss, ax;
    mov    sp, 0fff0h;

 

用前面提到的E820功能得到内存大小,把结果放在5000:1000处

    ; Use E820H of INT 15h to get the available memory
   mov     eax, 0E820h
   mov     ebx, 0
   mov     edi, MemTable;
   mov     ecx, 20;
   mov     edx, 'SMAP'

GetMemoryLayout:
    int     15h
    jc      ErrorGetMemoryLayout      ;Error
    and     ebx, ebx
    jz      EndGetMemoryLayout
    add     di, 20
    mov     eax, 0E820h
    jmp     GetMemoryLayout           ;Get next block

最后追加一个全0块作为结束标记(后面的C++代码会用到)

EndGetMemoryLayout:
    mov     dword ptr es:[di], 0
    mov     dword ptr es:[di + 4], 0
    mov     dword ptr es:[di + 8], 0
    mov     dword ptr es:[di + 12], 0

 

现在是时候切换入保护模式了,首先要关中断

    ; We have successfully got the memory layout. now, it's time to prepare to switch to protected mode
    cli                               ; disable interrupt

接下来打开A20  
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;A20 shall be enabled next
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Step1:
    call    Empty8042                ;we must wait until the buffer is empty
    mov     al,0d1h       
    out     64h,al
    call    Empty8042
    mov     al,0dfh
    out     60h,al
    call    Empty8042

 

设置全局描述符表,GDT_PTR中存放着描述符表的地址和长度

step2:
    lgdt    fword ptr [GDT_PTR]

 

设置段选择子,CS为内核代码段,DS,ES,GS为内核数据段,FS比较特殊,是为VC++的异常准备的

    ;Set all segment registers
    mov ax, 0010h
    mov ds, ax
    mov es, ax
    mov gs, ax
    mov ss, ax
    mov ax, 0018h
    mov fs, ax

设置控制寄存器,把CPU切换到保护模式

    mov     eax, cr0
    or      eax, 00000001h
    mov     cr0, eax

 

现在跳转到在61000的C++部分

    ; Jump to the C++ code of RMOSLDR
    db      66h, 0eah               ; The machine code for jump
    dd      61000h
    dw      0008h





   



这个子程序是打开A20门用的,现在看不懂没关系,当我们讲到键盘驱动的时候会再次提到这个8042控制器的
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Routine Empty8042
;This routine will empty the 8042 controller buffer, so that
;we can operate on A20 Gate
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Empty8042 PROC NEAR
        dw 00ebh, 00ebh         ;delay
        in al, 64h             ;check the 8042 status register
        test al, 2              ;check if the buffer is empty
        jnz Empty8042
        ret
Empty8042 ENDP







ErrorGetMemoryLayout:
   mov     si, offset ErrorGetMemoryLayoutMessage
   jmp     PrintError

PrintError:
   mov     ah, 0eh
   mov     al, [si]
   or      al, al
   jz      infloop
   int     10h
   inc     si
   jmp     PrintError
infloop:
   jmp     infloop



ErrorGetMemoryLayoutMessage:
   db "Cannot Get size of system memory", 0dh, 0ah, 0h

 

这里是描述符表,总共5个描述符
org 9000h
GDT_Table:
        dq      00000000000000000h     ; 00: NULL segment               [NULL_SELECTOR].
        dq      000CF9A000000FFFFh      ; 08: PM code segment          [PM_CODE_SELECTOR].
        dq      000CF92000000FFFFh      ; 10: PM data segment          [PM_DATA_SELECTOR].
        dq      000CF92005000FFFFh      ; 18: FS segment                   [PROCESSOR_SELECTOR].
        dq      00000000000000000h     ; 20                                        [UNUSED_SELECTOR].



GDT_PTR:
    dw      0800h
    dw      OFFSET GDT_Table , 5h
   


END start

 

 

所有的汇编语言程序到此结束,下面我们就要进入C++的天地了

原创粉丝点击