%include "protect.inc" ; 常量, 宏, 以及一些说明
org 0x0500
; 实模式
jmp SetUp_seg
;------------------------------------------------------------------------------------------
times 0x10-($-$$) db 0
KernelSize equ 512
; 此处地址: $ -> 0x500
MCRNumberDW: dd 0
MemChkBuf: times 256 db 0
MemSizeDW: dd 0
MemInfo1 db "________________________Memory Allocation_______________________"
MemInfoLen1 equ $ - MemInfo1
MemInfo2 db " BaseAddrLow BaseAddrHigh LengthLow LengthHigh Type"
MemInfoLen2 equ $ - MemInfo2
;
SetupMessage db "Running Setup ... "
SMLength equ $ - SetupMessage
KernelAddr equ 12*1024 ;将kernel加载到这里( 物理地址:12*1024 )
CylindTotalNum equ 80 ;软盘正反面都面有80个柱面
SectorTotalNum equ 18 ;软盘的每个磁道有18个扇区
SectorByte equ 512 ;软盘的每个扇区有512 byte
DriveNo db 0
HeadNo db 0
CylindNo db 0
SectorNo db 1
SectorNum db 0
LoadSeg dd 0
;------------------------------------------------------------------------------------------
PrintBlank:
push ax
push bx
mov bx, 000Ch
mov al, ' '
mov ah, 0Eh
int 10h
pop bx
pop ax
ret
;------------------------------
PrintRL:
push ax
push bx
push cx
push dx
mov ah, 03h
int 10h
inc dh
mov dl, 0
dec ah
int 10h
pop dx
pop cx
pop bx
pop ax
ret
;------------------------------
PrintMesg: ; 输出字符串函数
push bx
push es
mov ax, 00h
mov es, ax
mov ax, 1301h ; AH = 13, AL = 01h
mov bx, 000Ch ; 页号为0(BH = 0) 黑底红字(BL = 0Ch,高亮)
int 10h ; 10h 号中断
pop es
pop bx
ret
;------------------------------
PrintHex: ; 以十六进制的形式输出 AL
push bx
push cx
push dx
mov cx, 2
mov dh, al ; 用 dh 保存 al 的值
shr al, 4 ; 先输出高位
mov ah, 0Eh
.hex1:
and al, 0Fh
add al, '0'
cmp al, '9'
jbe .hex2
add al, 7 ; al 中的值大于 9 ,此时 al 已经 加了48
.hex2:
mov bx, 000Ch ; 字符属性
int 10h
mov al, dh
dec cx
jnz .hex1
pop dx
pop cx
pop bx
ret
;-------------------
ReadFloppy:
push es
.1
mov ax, word [LoadSeg]
mov es, ax
mov bx, 0
mov ah, 02h
mov al, [SectorNum]
mov dl, [DriveNo]
mov dh, [HeadNo]
mov ch, [CylindNo]
mov cl, [SectorNo]
int 13h
jc .1
pop es
ret
;----------------------------------------------------------------------------
SetUp_seg:
mov ax, cs
mov ds, ax
mov es, ax
mov ax, 8fc0h
mov ss, ax
mov sp, 0FFFFh
mov dx, 0200h ; dh -> 行号 dl -> 列号
mov bp, SetupMessage ; ES:BP = 串地址(ES == 0000h)
mov cx, SMLength
call PrintMesg
; 调用int 15h 中断获得内存使用情况,保存到 MemChkBu 中
mov ebx, 0
mov di, MemChkBuf
Chk_loop:
mov eax, 0E820h
mov ecx, 20
mov edx, 0534D4150h
int 15h
jc Chk_fail
add di, 20
inc dword [MCRNumberDW]
cmp ebx, 0
jne Chk_loop
jmp Mem_display
Chk_fail:
mov byte [MCRNumberDW], 0
; 显示内存可用情况
Mem_display:
; mov al ,byte [MCRNumberDW] ;memory info 个数
; call PrintHex
call PrintRL
mov dx, 0300h ; dh -> 行号 dl -> 列号
mov bp, MemInfo1 ; ES:BP = 串地址(ES == 0000h)
mov cx, MemInfoLen1
call PrintMesg
mov dx, 0500h ; dh -> 行号 dl -> 列号
mov bp, MemInfo2 ; ES:BP = 串地址(ES == 0000h)
mov cx, MemInfoLen2
call PrintMesg
mov dx, 0
mov dl, byte [MCRNumberDW]
cmp dl , 0
je Read_floppy
mov si, MemChkBuf
add si,4
Mem_L1:
call PrintRL
call PrintBlank
call PrintBlank
mov cx, 0
Mem_L2:
dec si
mov al, byte [si]
call PrintHex
inc cx
test cx, 0003h
jne Mem_L2
add si,8
call PrintBlank
call PrintBlank
call PrintBlank
call PrintBlank
call PrintBlank
call PrintBlank
cmp cx, 14h
jne Mem_L2
dec dx
jnz Mem_L1
;从软盘加载Kernel模块; 读内核到内存中 12*1024 处
Read_floppy:
mov [LoadSeg], word (KernelAddr-4*1024)/16
mov [SectorNum],byte 60 ; 13
mov [SectorNo],byte 6
call ReadFloppy
;软盘控制寄存器的I/O地址为3F0 - 3F7
mov dl, 0 ; 停止驱动器
mov dx, 0x3f2
mov al, 0x0c
out dx, al
;关中断
cli
;将在 Gdtr 放置的GDT 表入口(32位基址 + 16位界限)加载到----> gdtr(共48位)中
lgdt [Gdtr]
; 将GDT前八项到物理地址 0x000000 ,共 4 * 8byte = 32 byte
mov esi, Gdt_begin
mov edi, 0h
mov ecx, 10*8
cld
rep movsb
;打开地址线 A20
in al, 92h
or al, 02h
out 92h, al
;准备切换到保护模式
mov eax, cr0
or eax, 1
mov cr0, eax
; 将 Sel_code 装入 cs , 并入跳转到 KCode
jmp dword Sel_Kenel:KCode_start
; 保护模式
[bits 32]
KCode_start :
;初始化堆栈段 SS、SP 和 DS、ES
mov ax, Sel_KData ; Sel_KData 基址为 0000h
mov ds, ax
mov es, ax
mov ss, ax
mov esp, 140*1024-4
; 下面显示一个字符串: Running in Protect Mode now
mov ah, 0Ch ; 0000: 黑底 1100: 红字
mov esi, PMMessage ; 源数据偏移
mov edi, (80 * 12 + 0) * 2 ; 目的数据偏移。屏幕第 3 行, 第 0 列。
cld
PM_loop:
lodsb
test al, al
jz PM_end
mov [0xB8000+edi], ax
add edi, 2
jmp PM_loop
PM_end: ; 显示完毕
;-----------------------------------------
lidt [Idtr]
call SetupPageTbl ; 建立页表
mov eax, cr4
or eax, 20h
mov cr4, eax
mov eax, PagePDPEBase ;PageDirBase
mov cr3, eax
mov eax, cr0
or eax, 80000000h
mov cr0, eax
jmp dword Sel_Kenel:KernelAddr
Stop :
jmp $ ; 死循环
;
;------------------------------------------------------------------------------------------------------
; _________ 内存各段定义 _________
;
GDTBase equ 0
GDTLen equ 2*1024
;
IDTBase equ 2*1024
IDTLen equ 2*1024
;
PagePDPEBase equ 1024
PagePDEBase equ 4*1024
PagePTEBase equ 8*1024
;
PageNum equ 1 ; 页表个数,暂时为 1 个 (指向前4M内存),此处最多设为(640k-64k*2)/4k-1 = 127
;
; _________ GDT 定义 _________
; 段基址, 段界限, 属性
Gdt_begin :
Descriptor 0, 0, 0 ;0x0 空描述符
DesKCode : Descriptor 0, 0FFFFFh, Des_DPL0+Des_CR + Des_32 + Des_G ;0x8 (内核)非一致代码段, 32
DesKData : Descriptor 0, 0FFFFFh, Des_DPL0+Des_DRW + Des_32 + Des_G ;0x10
Gdt_end
;
Gdtr :
dw GDTLen ; gdt的长度
dd GDTBase ; gdt的物理地址
Idtr :
dw IDTLen-1 ; idt的长度
dd IDTBase ; idt的物理地址
Sel_Kenel equ DesKCode - Gdt_begin
Sel_KData equ DesKData - Gdt_begin ; 数据段描述符
Sel_stack equ DesKData - Gdt_begin ; 堆栈段描述符
;
PMMessage db "Running in ProtectMode",0
;----------------------------------------------------------------------------------------------------
; 初始化页表
SetupPageTbl:
mov dword [PagePDPEBase+4] , dword 0x0
mov dword [PagePDPEBase], PagePDEBase | PG_P | PG_USU | PG_RWW
mov dword [PagePDEBase+4] , dword 0x0
mov dword [PagePDEBase] , PagePTEBase | PG_P | PG_USU | PG_RWW
mov ecx, 512 ; 每个页表有 1024 项, 每项 4 byte
mov edi, PagePTEBase ; 此段首地址为 PagePTEBase
xor eax, eax
mov eax, PG_P | PG_USU | PG_RWW
.PageTbl:
mov [es:edi], eax
add edi,4
mov [es:edi], dword 0x0
add edi,4
add eax, 4096 ; 每一页指向 4K 的空间
loop .PageTbl
call deleteHole
ret
deleteHole:
mov esi, PagePTEBase + 35*8 ;// 140k 对应的页表项 140 = 4k + 4k + 4k + 128k
mov edi, PagePTEBase + 160*8 ;// 640k 对应的页表项
mov ecx, (1024-640)/4
.1
mov eax, dword [esi]
mov ebx, dword [edi]
mov dword [esi], ebx
mov dword [edi], eax
add edi,8
add esi,8
loop .1
ret
;------------------------------
times 2048-($-$$) db 0