原文地址:http://blog.csdn.net/ltbylc/article/details/8292922
0. 自己试着在win7下用NASM和minGW改写汇编和C混合编程,结果受挫了。还是先使用作者提供的工具构建吧。
1. 通过前2天的工作已经能使用NASM制作一个映像了,并且编写的汇编代码可以成为引导扇区代码。
2. 引导扇区代码中可以调用BIOS中断,读取软盘上其它扇区到内存中,根据FAT12文件系统格式得知,保存到软盘内的第一个文件的文件名一定从19逻辑扇区开始,且该文件的内容从逻辑扇区33开始。
3. 引导扇区可以将第一个保存的文件(kernel.sys=自己改的名字,功能是跳入保护模式并调用C语言编写的函数代码)读入内存并使之执行,找这个文件用到了一个技巧,不然通过文件系统结构分析出文件位置,并加载码就太复杂了。
4. 引导扇区代码如下ipl10.asm
; haribote-ipl
; TAB=4
CYLS EQU 10
ORG 0x7c00
JMP entry
DB 0x90
DB "HARIBOTE"
DW 512
DB 1
DW 1
DB 2
DW 224
DW 2880
DB 0xf0
DW 9
DW 18
DW 2
DD 0
DD 2880
DB 0,0,0x29
DD 0xffffffff
DB "HARIBOTEOS "
DB "FAT12 "
RESB 18
entry:
MOV AX,0
MOV SS,AX
MOV SP,0x7c00
MOV DS,AX
MOV AX,0x0820
MOV ES,AX
MOV CH,0
MOV DH,0
MOV CL,2
readloop:
MOV SI,0
retry:
MOV AH,0x02
MOV AL,1
MOV BX,0
MOV DL,0x00
INT 0x13
JNC next
ADD SI,1
CMP SI,5
JAE error
MOV AH,0x00
MOV DL,0x00
INT 0x13
JMP retry
next:
MOV AX,ES
ADD AX,0x0020
MOV ES,AX
ADD CL,1
CMP CL,18
JBE readloop
MOV CL,1
ADD DH,1
CMP DH,2
JB readloop
MOV DH,0
ADD CH,1
CMP CH,CYLS
JB readloop
MOV [0x0ff0],CH
JMP 0xc200
error:
MOV SI,msg
putloop:
MOV AL,[SI]
ADD SI,1
CMP AL,0
JE fin
MOV AH,0x0e
MOV BX,15
INT 0x10
JMP putloop
fin:
HLT
JMP fin
msg:
DB 0x0a, 0x0a
DB "load error"
DB 0x0a
DB 0
;RESB 0x7dfe-$
times 510-($-$$) db 0
DB 0x55, 0xaa
5. 跳入保护模式代码如下asmhead.nas
(1)准备GDT
(2)用LGDT加载gdtr
(3)打开A20
(4)设置CR0的PE位
(5)跳转进入保护模式
; haribote-os boot asm
; TAB=4
BOTPAK EQU 0x00280000
DSKCAC EQU 0x00100000
DSKCAC0 EQU 0x00008000
CYLS EQU 0x0ff0
LEDS EQU 0x0ff1
VMODE EQU 0x0ff2
SCRNX EQU 0x0ff4
SCRNY EQU 0x0ff6
VRAM EQU 0x0ff8
ORG 0xc200 ;让引导扇区加载后从这里开始运行
MOV AL,0x13 ;保存信息
MOV AH,0x00
INT 0x10
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
MOV AL,0xff
OUT 0x21,AL
NOP
OUT 0xa1,AL
CLI
CALL waitkbdout
MOV AL,0xd1
OUT 0x64,AL
CALL waitkbdout
MOV AL,0xdf ; enable A20
OUT 0x60,AL
CALL waitkbdout
[INSTRSET "i486p"]
LGDT [GDTR0]
MOV EAX,CR0
AND EAX,0x7fffffff
OR EAX,0x00000001
MOV CR0,EAX
JMP pipelineflush
pipelineflush:
MOV AX,1*8
MOV DS,AX
MOV ES,AX
MOV FS,AX
MOV GS,AX
MOV SS,AX
MOV ESI,bootpack
MOV EDI,BOTPAK
MOV ECX,512*1024/4
CALL memcpy
MOV ESI,0x7c00
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 EBX,BOTPAK
MOV ECX,[EBX+16]
ADD ECX,3
SHR ECX,2
JZ skip
MOV ESI,[EBX+20]
ADD ESI,EBX
MOV EDI,[EBX+12]
CALL memcpy
skip:
MOV ESP,[EBX+12]
JMP DWORD 2*8:0x0000001b
waitkbdout:
IN AL,0x64
AND AL,0x02
JNZ waitkbdout
RET
memcpy:
MOV EAX,[ESI]
ADD ESI,4
MOV [EDI],EAX
ADD EDI,4
SUB ECX,1
JNZ memcpy
RET
ALIGNB 16
GDT0:
RESB 8
DW 0xffff,0x0000,0x9200,0x00cf
DW 0xffff,0x0000,0x9a28,0x0047
DW 0
GDTR0:
DW 8*3-1
DD GDT0
ALIGNB 16
bootpack:
6. C语言代码如下bootpack.c
void io_hlt(void);
void write_mem8(int addr,int data);
void HariMain(void)
{
int i;
for(i=0xa0000;i<=0xaffff;i++)
{
write_mem8(i,15);
}
for(;;)
{
io_hlt();
}
}
7. C语言中调用的io_hlt和write_mem8函数放到了如下代码中func.asm
[FORMAT "WCOFF"]
[INSTRSET "i486p"]
[BITS 32]
[FILE "naskfunc.nas"]
global _io_hlt,_write_mem8
[section .text]
;void io_hlt(void);
_io_hlt:
HLT
RET
;void write_mem8(int addr,int data);
_write_mem8:
MOV ECX,[ESP+4]
MOV AL,[ESP+8]
MOV [ECX],AL
RET
8. 在toolset文件夹内建立一个新文件夹,将上面所有的文件放在里边,编译链接接上面的文件,写个bat文件如下
nasm -o ipl10.bin ipl10.asm
nasm -o img.img img.asm
..\z_tools\nask.exe asmhead.nas asmhead.bin
..\z_tools\cc1.exe -I..\z_tools\haribote\ -Os -Wall -quiet -o bootpack.gas bootpack.c
..\z_tools\gas2nask.exe -a bootpack.gas bootpack.nas
..\z_tools\nask.exe bootpack.nas bootpack.obj
..\z_tools\nask.exe func.asm func.obj
..\z_tools\obj2bim.exe @..\z_tools\haribote\haribote.rul out:bootpack.bim stack:3136k map:bootpack.map bootpack.obj func.obj
..\z_tools\bim2hrb.exe bootpack.bim bootpack.hrb 0
copy /B asmhead.bin+bootpack.hrb kernel.sys
9.这样除了中间文件外,生成img.img文件和kernel.sys文件。使用winImage打开img.img文件将kernel.sys文件加入到该img文件中。
10. 启动Bochs,呵呵看见屏幕白了,这可是从C代码里控制的啊!
11. asmhead中跳入保护模式的代码慢慢在深入掌握,不然会掉入细节里不能自拔了。
12. asmhead和C代码是通过copy /B进行链接的其中asmhead代码最后留了个标号bootpack,在这个标号后面C的目标代码被砍去文件头直接将代码链接到了这里,所以能实现从汇编跳转到C语言的目的。