读书笔记《30天自制操作系统》day03

0. 自己试着在win7下用NASM和minGW改写汇编和C混合编程,结果受挫了。还是先使用作者提供的工具构建吧。

1. 通过前2天的工作已经能使用NASM制作一个映像了,并且编写的汇编代码可以成为引导扇区代码。

2. 引导扇区代码中可以调用BIOS中断,读取软盘上其它扇区到内存中,根据FAT12文件系统格式得知,保存到软盘内的第一个文件的文件名一定从19逻辑扇区开始,且该文件的内容从逻辑扇区33开始(见day01,图一)。

3. 引导扇区可以将第一个保存的文件(asmhead.nas,功能是跳入保护模式并调用C语言编写的函数代码)读入内存并使之执行,找这个文件用到了一个技巧(如2描述),不然通过文件系统结构分析出文件位置,并加载码就太复杂了。

4. 引导扇区代码如下ipl10.asm

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	   ;读1个扇区		
		MOV		BX,0       ;目的地址
		MOV		DL,0x00	   ;驱动器号		
		INT		0x13	   ;来BIOS中断		
		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   ;保存位置向后移动512字节,0x0020是段地址加偏移量后成为0x0200了
		MOV		ES,AX			
		ADD		CL,1			
		CMP		CL,18       ;读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        ;跳到软盘kernel.sys(asmhead.nas+bootpack.c)文件内部执行
                                              ;该文件在加载软盘文件基址0x8000+Fat12文件系统中文件出现位置0x004200处=0xc200H
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

BIOS 13中断说明(功能有磁盘的读、写、扇区校验、寻道)
AH=0x02 读盘/0x03写盘/0x04校验/0x0c寻道
AL=处理连续扇区数
CH=柱面号&0xff
CL=扇区号(0~5位)|(柱面号&0x300)>>2
DH=磁头号
DL=驱动器号
ES:BX=缓冲地址
返回值:FLAGS=0没有错误AH=0,FLAGS=1有错误AH保存错误码

 

5. 跳入保护模式代码如下asmhead.nas(1)准备GDT(2)用LGDT加载gdtr(3)打开A20(4)设置CR0的PE位(5)跳转进入保护模式

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                 ;禁止PIC主从片的中断
      		OUT		0x21,AL
		NOP					;不能有两个连续的OUT指令
		OUT		0xa1,AL

		CLI		                        ;禁止PIC工作要在CLI之前				



		CALL	waitkbdout                      ;等待键盘电路准备好,要设置A20使1MB以上内存能被访问
		MOV		AL,0xd1
		OUT		0x64,AL
		CALL	waitkbdout
		MOV		AL,0xdf			; enable A20
		OUT		0x60,AL
		CALL	waitkbdout


[INSTRSET "i486p"]				

		LGDT	[GDTR0]			        ;加载临时的GDT表首地址到GDTR寄存器
		MOV		EAX,CR0
		AND		EAX,0x7fffffff	
		OR		EAX,0x00000001	
		MOV		CR0,EAX                 ;设置CR0寄存器PE标志位
		JMP		pipelineflush           ;设置标志位之后马上JMP
pipelineflush:                                          ;从此寻址方式变了
		MOV		AX,1*8                  ;段值的设置,用GDT中那个段(GDT+1段)			
		MOV		DS,AX
		MOV		ES,AX
		MOV		FS,AX
		MOV		GS,AX
		MOV		SS,AX



		MOV		ESI,bootpack	        ;将bootpack.c生成的目标代码移动到0x00280000,乾坤大挪移
		MOV		EDI,BOTPAK		
		MOV		ECX,512*1024/4
		CALL	memcpy



		MOV		ESI,0x7c00              ;将启动扇区复制到1MB以后的内存		
		MOV		EDI,DSKCAC		
		MOV		ECX,512/4
		CALL	memcpy


		MOV		ESI,DSKCAC0+512	        ;将0x00008200数据复制到0x00100200
		MOV		EDI,DSKCAC+512	
		MOV		ECX,0
		MOV		CL,BYTE [CYLS]
		IMUL	        ECX,512*18*2/4	
		SUB		ECX,512/4		
		CALL	memcpy
                ;至此内存中0x00100000部分与磁盘内容就一样了
   
                ;调用bootpack.c的初始化操作,解析bootpack.hrb的header并传入参数
		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          ;跳到指定段中跳过可执行文件头p421

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:                                                            ;临时设计的GDT表
		RESB	8				
		DW		0xffff,0x0000,0x9200,0x00cf	
		DW		0xffff,0x0000,0x9a28,0x0047	

		DW		0
GDTR0:                                                           ;临时设计的GDT选择子
		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);        /*向内存的0xa0000~0xaffff位置写入信息,这块内存是显存空间,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语言的目的。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值