上一段时间碰到一个问题,摸索了好长时间,原来是ld链接器对地址的定位,与我把程序的加载地址冲突,所以访问不到正确的位置,引起的。等碰到这个问题再说啦。
到达这里我们基本上已经完成了操作系统内核之前的准备了。我们就准备跳转到32位模式下啦。ok,让我们先考虑下进入32位模式之前需要做些什么
1.应该禁用pic(Programmable Interrupt Controller)中断,以避免有问题(虽然不禁用,暂时没发现什么问题)
2.开启A20Gate
3.初始化GDT
4.置CR0寄存器保护模式位
4.跳转啦
解释:为什么要禁用中断呢,嘿嘿,我也不知道。不过据说是:根据AT兼容机的规格, 初始化PIC必须在CLI之前进行,否则有时候会被挂起,随后进行PIC的初始化
代码为
-
mov AL,0xff
-
out 0x21,AL ;pic0的端口
-
NOP ;等会儿嘛,太快了,可能出问题
-
out 0xal,al ;pic1的端口
-
cli ;禁用可屏蔽中断
pic有两个芯片的,一个是master一个slave在这里就不做详细的讨论啦。给个网址大家去看 http://wiki.osdev.org/PIC
然后是开启A20啦,因为之前只能访问1M的内存嘛(2的20次方),请参照 http://wiki.osdev.org/A20.
-
;开启A20管脚 初始化GDT和CR0,我们开始初始化两个段,一个代码段一个数据段。看之前请参照
-
CALL waitkbdout
-
MOV AL,0xd1
-
OUT 0x64,AL ;其实管脚的控制在键盘的芯片里面
-
CALL waitkbdout
-
MOV AL,0xdf ;enable A20
-
OUT 0x60,AL
-
CALL waitkbdout
-
waitkbdout:
-
IN AL,0x64
-
AND AL,0x02
-
JNZ waitkbdout ;
-
RET
初始化GDT和CR0,我们开始初始化两个段,一个代码段一个数据段。看之前请参照 http://wiki.osdev.org/GDT,我们以后还会讲的
-
LGDT [GDTR0] ; 加载gd
-
MOV EAX,CR0
-
AND EAX,0x7fffffff ;禁止分页
-
OR EAX,0x00000001 ; 开启保护模式
-
MOV CR0,EAX
-
ALIGNB 16
-
GDT0:
-
RESB 8 ;第一项为0,规定这样
-
-
DW 0xffff,0x0000,0x9200,0x00cf ; 数据
-
DW 0xffff,0x0000,0x9a28,0x0047 ; 可执行
-
DW 0
-
GDTR0:
-
DW 8*3-1;gdt的大小
-
DD GDT0;起始地址
-
ALIGNB 16
然后我决定可以把我们的程序移位到另一个地址,在此之前先刷新一下段寄存器吧大家读过linux内核源码的估计会记得置位CR0的保护位用的是lmsw,那是古老的方式啦。
-
MOV AX,1*8 ; 段偏移量
-
MOV DS,AX
-
MOV ES,AX
-
MOV FS,AX
-
MOV GS,AX
-
mov ax,AX
-
MOV SS,AX
然后是移位啦
-
BOTPAK EQU 0x00280000 ; 我们主程序load地址
-
DSKCAC EQU 0x00100000 ;
-
DSKCAC0 EQU 0x00008000 ;
-
MOV ESI,bootpack ; 把我们的主程序加载到0x280000,我们会把32位的代码放到bootpack后边
-
MOV EDI,BOTPAK ;
-
MOV ECX,512*1024/4
-
CALL memcpy
-
-
MOV ESI,0x7c00 ;把boot程序加载到DSKCAC
-
MOV EDI,DSKCAC ;
-
MOV ECX,512/4
-
CALL memcpy
-
-
MOV ESI,DSKCAC0+512 ; 把其余的也加载进来
-
MOV EDI,DSKCAC+512 ;
-
MOV ECX,0
-
MOV CL,BYTE [CYLS]
-
IMUL ECX,512*18*2/4 ;
-
SUB ECX,512/4 ;
-
CALL memcpy
-
-
memcpy:
-
cld ;清方向
-
a32 rep movsd
-
RET
最后先写一个32位的汇编会跳到这里kernelFunc.asm,我们会让屏幕变个颜色的
-
[bits 32]
-
hah:
-
MOV eAX,1*8 ; 段偏移量 ,还是在这再初始化一次吧
-
MOV DS,AX
-
MOV ES,AX
-
MOV FS,AX
-
MOV SS,AX
-
mov esp,0x280000;把栈地址放到这把
-
mov eax ,0xa0000
-
loops:
-
mov byte [eax],14
-
inc eax
-
cmp eax, 0xaffff
-
jbe loops
-
jmp loo
-
-
loo:
-
hlt
-
jmp loo
然后写一个脚本吧 build.bat如在linux请先安装nasm,然后自己写一个makefile
-
rem 我们的bootloader
-
nasm -o .\bin\begin.bin begin.asm
-
rem 我们的入口
-
nasm -o haribote.o haribote.asm
-
rem 我们的32位入口
-
nasm -o kernelFunc.o kernelfunc.asm
-
rem copy二进制内容到一个地方
-
copy /B haribote.o+kernelFunc.o kernel
至此全部haribote.asm的内容如下:
-
; haribote-os boot asm
-
; TAB=4
-
BOTPAK EQU 0x00280000 ; 我们主程序load地址
-
DSKCAC EQU 0x00100000 ;
-
DSKCAC0 EQU 0x00008000 ;
-
-
CYLS EQU 0x0ff0 ; 柱面数
-
LEDS EQU 0x0ff1 ;le灯
-
VMODE EQU 0x0ff2 ; 模式
-
SCRNX EQU 0x0ff4 ; x的分辨率
-
SCRNY EQU 0x0ff6 ; y的分辨率
-
VRAM EQU 0x0ff8 ;起始地址
-
ORG 0xc200 ;程序开始的地址
-
MOV AL,0x13 ;
-
MOV AH,0x00
-
INT 0x10 ;转化成图像模式的320*200*8bit
-
MOV BYTE [VMODE],8 ;
-
MOV WORD [SCRNX],320
-
MOV WORD [SCRNY],200
-
MOV DWORD [VRAM],0x000a0000
-
;
-
MOV AH,0x02
-
INT 0x16 ; keyboard BIOS
-
MOV [LEDS],AL
-
-
;禁用pic中断
-
MOV AL,0xff
-
OUT 0x21,AL
-
NOP ;
-
OUT 0xa1,AL
-
CLI ; 禁用可屏蔽中断
-
-
;开启A20管脚
-
CALL waitkbdout
-
MOV AL,0xd1
-
OUT 0x64,AL
-
CALL waitkbdout
-
MOV AL,0xdf ; enable A20
-
OUT 0x60,AL
-
CALL waitkbdout
-
LGDT [GDTR0] ;
-
MOV EAX,CR0
-
AND EAX,0x7fffffff ;禁止分页
-
OR EAX,0x00000001 ; 开启保护模式
-
MOV CR0,EAX
-
MOV AX,1*8 ; 段偏移量
-
MOV DS,AX
-
MOV ES,AX
-
MOV FS,AX
-
MOV GS,AX
-
mov ax,AX
-
MOV SS,AX
-
-
MOV ESI,bootpack ; 把我们的主程序加载到0x280000
-
MOV EDI,BOTPAK ;
-
MOV ECX,512*1024/4
-
CALL memcpy
-
-
MOV ESI,0x7c00 ;把boot程序加载到DSKCAC
-
MOV EDI,DSKCAC ;
-
MOV ECX,512/4
-
CALL memcpy
-
-
MOV ESI,DSKCAC0+512 ; 把其余的也加载进来
-
MOV EDI,DSKCAC+512 ;
-
MOV ECX,0
-
MOV CL,BYTE [CYLS]
-
IMUL ECX,512*18*2/4 ;
-
SUB ECX,512/4 ;
-
CALL memcpy
-
-
MOV esp,0x000280000
-
-
JMP dword 16:0x00000000;dword必须的,表示段间转移
-
-
waitkbdout:
-
IN AL,0x64
-
AND AL,0x02
-
JNZ waitkbdout ;
-
RET
-
memcpy:
-
cld
-
a32 rep movsd
-
RET
-
-
ALIGNB 16
-
GDT0:
-
RESB 8 ;
-
DW 0xffff,0x0000,0x9200,0x00cf ; 数据
-
DW 0xffff,0x0000,0x9a28,0x004f ; 可执行
-
DW 0
-
GDTR0:
-
DW 8*3-1
-
DD GDT0
-
ALIGNB 16
-
bootpack:
然后用winImage把boot加载进去,然后选择Image下面的Inject把我们的 kernel注入进去,用虚拟机加载一把吧,会有奇迹发生的。嘿嘿。今天就到这里吧。有问题请提问哈。
阅读(1231) | 评论(0) | 转发(0) |