二、init.asm初始化操作系统内存。进入32位保护模式
[BITS 16]
[ORG 0x0]
JMP main
;-----------------------------------------------------------
;操作系统内存结构
;0x0-0x3FFF ;堆栈16kb
;0x4000-0x40ff ;鼠标指针数据256byte
;0x4100-0x90ff ;图像缓冲区20kb
;0x9100-0x9fff ;init模块3kb
;0x10000:0x2ffff;64kb系统内存包括声卡内存数据信息.前10kb给系统表使用4k给声卡用
;变量从0x13800开始申请50kb
;20000-0x61600 ;图文字库用的ucdos字库 262.5kb
;0x61610-0x9FFFF;系统内核250.5kb
;0x9ffff
;a0000-1f0000 ;1.34mb未申请的内存
;0x100000 ;显示缓存跳过未申请的内存区
;-----------------------------------------------------------
;GDT表定义:
;为了能让内存对其方式为2的幂次所以第一个GDT结构要定义成空
GDTTABLE:
GDT0:
DD 0
DD 0
GDT_CODE_SEGMENT_POS equ $-GDTTABLE
GDT_CODE_SEGMENT:
DW 0xffff ;0到0xffff也就是0x10000*4KB大小。这个段可以访问4个GB
DW 0x1610
DB 0x06
DB 10011010B ;GDT表详细描述中有详细注释
DB 11001111B ;设置为一个表限制为1*4KB,数据段为32位,其他为0
DB 0
GDT_DATA_SEGMENT_POS equ $-GDTTABLE
GDT_DATA_SEGMENT:
DW 0xffff
DW 0x0000
DB 0x0
DB 10010010B ;注意这个是数据段有一个标志位和代码段是不同的
DB 11001111B
DB 0
GDT_VESA_MEM_POS equ $-GDTTABLE ;b800的位置用来现实文字
GDT_VESA_MEM:
DW 0xFFFF
DW 0x0000 ;0xb800转换成线性地址乘10h
DB 0x0 ;意思也就是这个结构的线性地址从物理内存的b800处开始映射
DB 10010010B
DB 11001111B
DB 0
GDT_END:
GDT_ADDR: ;这个也是固定结构,cpu读取GDT表必须要用的
DW GDT_END - GDTTABLE -1 ;GDT 表的大小这里1个=8个字节。也就是代表有多少个GDT项.
;一个GDT项为8个字节组成
DD GDTTABLE+0x9100 ;GDT表的地址
;--------------------------------------------------------------------------------------------------------
VBE_ADDR: EQU 0x1380
;-------------------------------------------------------------------------------------
;PUSH 磁头号 WORD
;PUSH segment WORD
;PUSH offset WORD
;PUSH driver WORD
;PUSH 起始磁道 WORD
;PUSH 起始扇区 WORD
;PUSH 读取多少个扇区 WORD
ReadDriver:
PUSH BP
MOV BP,SP
read:
MOV AX,WORD [ESP+14] ;获得欲拷贝的段地址
MOV ES,AX
MOV BX,WORD [ESP+12] ;拷贝地址的偏移
MOV AH,2
MOV DH,BYTE [ESP+16] ;磁头号
MOV DL,BYTE [ESP+10] ;驱动器
MOV CH,BYTE [ESP+8] ;第几个磁道开始读取
MOV CL,BYTE [ESP+6] ;从第4个扇区开始读
MOV AL,BYTE [ESP+4] ;读入扇区数,每个扇区为 512B*8.
INT 0x13 ;调用13中断读取磁盘信息
JC read
MOV SP,BP
POP BP
ret 14
;--------------------------------------------------------------------------------------------
main:
MOV ESP,0xFFFF
MOV AX,0x910
MOV DS,AX
;读取鼠标光标
PUSH WORD 0 ;0
PUSH WORD 0x1000 ;存入段地址
PUSH WORD 0 ;存入的偏移
PUSH WORD 0 ;驱动器
PUSH WORD 0 ;起始磁道
PUSH WORD 12 ;起始扇区
PUSH WORD 1 ;读取扇区数量
CALL ReadDriver
;移动512字节的各部分数据到相应的内存
PUSH DS
PUSH ES
XOR ECX,ECX
XOR EAX,EAX
XOR ESI,ESI
XOR EDI,EDI
MOV AX,0x1000
MOV ES,AX
MOV AX,0x400
MOV DS,AX
MOV EAX,[ES:0] ;移动鼠标点阵到0x4000处
MOV [DS:0],DWORD EAX
MOV EAX,[ES:4]
MOV [DS:4],DWORD EAX
;MOV CX,2
;MOV AX,0x1000 ;复制原
;MOV DS,AX
;MOV AX,0x400
;MOV ES,AX ;目标
;REP
POP ES
POP DS
;PUSH WORD 0
;PUSH WORD 0x20A0 ;存入段地址
;PUSH WORD 0 ;存入的偏移
;PUSH WORD 0 ;驱动器
;PUSH WORD 1 ;起始磁道
;PUSH WORD 1 ;起始扇区
;PUSH WORD 18 ;读取扇区数量
;CALL ReadDriver
;读取字库0
PUSH WORD 0
PUSH WORD 0x2000 ;存入段地址
PUSH WORD 0 ;存入的偏移
PUSH WORD 0 ;驱动器
PUSH WORD 0 ;起始磁道
PUSH WORD 13 ;起始扇区
PUSH WORD 24 ;读取扇区数量
CALL ReadDriver
MOV AX,0x2780
MOV ES,AX
MOV CX,2 ;起始磁道
rlop:
PUSH WORD 0x910
POP DS ;恢复数据段寄存器
PUSH CX
PUSH ES
PUSH WORD 0
PUSH WORD 0x2300 ;存入段地址
PUSH WORD 0 ;存入的偏移
PUSH WORD 0 ;驱动器
PUSH CX ;起始磁道
PUSH WORD 1 ;起始扇区
PUSH WORD 37 ;读取扇区数量
CALL ReadDriver
MOV AX,0x2300
MOV DS,AX
XOR SI,SI
XOR DI,DI
POP ES
MOV CX,0x2500
CLD
REP MOVSW
MOV AX,ES
ADD AX,0x4A0
MOV ES,AX
PUSH WORD 0x910
POP DS ;恢复数据段寄存器
POP CX
INC CX
CMP CX,16 ;循环2-15次
JNZ rlop
PUSH WORD 0
PUSH WORD 0x2300 ;存入段地址
PUSH WORD 0 ;存入的偏移
PUSH WORD 0 ;驱动器
PUSH WORD 1 ;起始磁道
PUSH WORD 1 ;起始扇区
PUSH WORD 36 ;读取扇区数量
CALL ReadDriver
;读取内核
PUSH WORD 0 ;磁头号0
PUSH WORD 0x6161 ;存入段地址
PUSH WORD 0 ;存入的偏移
PUSH WORD 0 ;驱动器
PUSH WORD 0 ;起始磁道
PUSH WORD 4 ;起始扇区
PUSH WORD 8 ;读取扇区数量01010101
CALL ReadDriver
MOV DX,0x3F2 ;关闭软区马达
MOV AL,0
OUT DX,AL
;-----------------------------------------------------------------------------------------------------
;设置现卡模式
;-----------------------------------------------------------------------------------------------------
;设置显卡模式
MOV AX , 0x4f02
MOV BX , 0x4114 ;800 * 600 16位色( 5:6:5 )
int 0x10 ;设置显示模式
;取得该模式下显存线性地址
PUSH DS
POP ES
;MOV BX,0x0
;MOV ES,BX
MOV DI,VBE_ADDR ;用来存放vesa信息的结构
MOV AX,0x4f01
MOV CX,0x114
INT 0x10
MOV EAX,[VBE_ADDR + 40] ;获得直接色彩模式属性(结构第40个字节)
MOV BX,0x1380 ;一个DWORD型的显存地址放到0x1380:0的位置
MOV ES,BX ;设置段地址
MOV [ES:0],EAX
;进入32位保护模式
;关闭一切设备的输入
LGDT [GDT_ADDR] ;装载GDT表
CLI
IN AL,0x92 ;打开a20地址总线的为访问更多内存
OR AL,2 ;第2个二进制位
OUT 0x92,AL ;打开32位模式
MOV EAX,CR0 ;进入模式
OR EAX,1 ;打开寄存器cr0中的第一个二进制位
MOV CR0,EAX ;把修改好的内容写回去就进入32位保护模式了
STI
;接下来执行32位代码
JMP DWORD GDT_CODE_SEGMENT_POS:0
TIMES 0x400-($-$$) DB 0