查看: 65520|回复: 915

自己动手写操作系统系列之----------加载Kernel

[复制链接]
发表于 2015-11-8 09:46:39 | 显示全部楼层 |阅读模式
本帖最后由 冰琥珀 于 2015-11-8 10:13 编辑

       上一篇文章写了Loader.bin文件的加载,我们也成功的将控制权转交给Loader.bin,接下来就通过它来加载内核,在这里,我们将要完成的只是将内核的数据加载到内存,加载完了之后,我们进行一些其他的处理之后,再在内存中调整内核,为啥要调整内核,因为内核是一个elf文件(就像windows下的pe文件),要使其能够运行,就需要按照elf的文件格式,将各个段映射到内存中,这个我们在加载完内核之后会做处理。也许有人会问,为啥Loader.bin不用做处理,因为Loader.bin我们是将其编译成com文件,所以不需要像elf文件那样按段加载到内存中。现在先来完成内核的加载。
        内核的加载方式和Loader.bin的方式一样,都是在根目录中查找到”KERNEL   BIN”的目录项,然后读取处初始簇号,再根据簇号来加载数据,同时在FAT中查找下一个簇号,如果还有下一个簇号,则继续加载,否则加载结束。流程上跟Loader.bin的加载是一样的,我们先来看代码
[AppleScript] 纯文本查看 复制代码
org 0x100
	
	jmp		LABEL_START		;跳转

	BaseOfStack		equ		0x100
	BaseOfKernel	equ		0x8000
	OffsetOfKernel	equ		0
	wRootSecCnt		dw		0
	wRootCurSecNum	dw		0
	wReadOffset		dw		0
	wFileNameCnt	db		0
	bInHighByte		db		0			
	LoaderFileName	db		'KERNEL  BIN', 0	;LOADER.BIN (文件名)
	MessageLength	equ		9
	BootMessage:	db		"Loading  "
	Message1:		db		"Ready.   "
	Message2:		db		"No KERNEL"

	%include "Include/FAT12Info.inc"		

LABEL_START:
	mov ax, cs
	mov ds, ax
	mov es, ax
	mov ss, ax
	mov sp, BaseOfStack

	;显示Loading  
	mov dh, 0
	call DispStr

	mov word [wRootCurSecNum], RootDirSecNum
	mov word [wRootSecCnt], RootDirSecCnt
LABEL_SEARCH_IN_ROOT_DIR_BEGIN:
	cmp word [wRootSecCnt], 0
	jz	LABEL_SEARCH_IN_ROOT_DIR_END	;这里跳转表示整个根目录都搜索完毕,没有找到Loader.bin

	
	dec word [wRootSecCnt]
	mov	ax, BaseOfKernel
	mov es, ax
	mov bx, OffsetOfKernel
	mov ax, word [wRootCurSecNum]
	mov cl, 1
	call ReadSector				;读取扇区数据
	mov di, OffsetOfKernel
	cld
	mov dl, 0x10				;每个扇区中目录个数为16

LABEL_CMP_NEXT_FILE_NAME:
	mov si, LoaderFileName
	mov cl, 0x0b				;文件名长度为11个字节

LABEL_CMP_FILE_NAME:
	test cl, cl
	jz LABEL_FOUND_LOADER
	dec cl
	lodsb
	test al, al
	jz LABEL_CMP_NAME_END		;文件名比较完毕
	cmp al, [es:di]
	jz LABEL_GO_ON		;从根目录中读取到的文件名字符和目标文件名字符相等,则继续比较下一个字符

	jmp LABEL_CMP_NAME_END

LABEL_GO_ON:
	inc di
	jmp LABEL_CMP_FILE_NAME

LABEL_CMP_NAME_END:
	dec dl
	jz LABEL_GO_TO_NEXT_SECTOR	;16组目录都比较完毕,则读取下一个扇区
	and di, 0xffe0				;这里把di指针重置到当前目录的起始处
	add di, 0x20				;指针指向下一组目录(每组目录长度为32个字节)
	jmp	LABEL_CMP_NEXT_FILE_NAME	;比较下一组文件名

LABEL_GO_TO_NEXT_SECTOR:
	inc word [wRootCurSecNum]
	jmp LABEL_SEARCH_IN_ROOT_DIR_BEGIN

LABEL_SEARCH_IN_ROOT_DIR_END:	;没找到LOADER.BIN
	mov dh, 2
	call DispStr

	jmp $

LABEL_FOUND_LOADER:				;找到LOADER.BIN文件
	xor cx, cx
	and di, 0xffe0				;这里把di设置为指向目录项的首地址
	add di, 0x1a				;目录项中偏移0x1a处为初始簇号
	mov cx, word [es:di]		;将初始簇号存入cx
	mov word [wReadOffset], OffsetOfKernel

LABEL_GO_ON_LOADING:
	push ax
	push bx
	mov ah, 0x0e
	mov al, '.'
	mov bl, 0x0f
	int 0x10
	pop bx
	pop ax

	push cx
	mov ax, cx
	sub ax, 2
	xor cx, cx
	mov cl, [BPB_SecPerClus]
	mul cl
	mov bx, DataOffsetSec
	add ax, bx						;得到当前簇号的数据偏移(单位:扇区)
	push ax
	mov ax, BaseOfKernel
	mov es, ax					;存放数据的段地址
	pop ax
	mov bx, word [wReadOffset]		;存放数据的偏移
	mov cl, 1
	call ReadSector				;读取数据
	
	pop ax						;取出当前簇号
	mov bx, 3					
	mul bx						;簇号 * 3
	mov bx, 2
	div bx						;再除2,这里得到簇号的偏移(单位:字节)				
	test dx, dx
	jz LABEL_IN_HIGH_BYTE
	mov byte [bInHighByte], 1	;该簇号的在当前字节的高4位

LABEL_IN_HIGH_BYTE:
	xor dx, dx
	mov bx, [BPB_BytePerSec]
	add word [wReadOffset], bx	
	div bx
	inc ax						;FAT	
	push dx
	push ax
	mov ax, BaseOfKernel
	sub ax, 0x100
	mov es, ax					;设置读的位置的段地址
	pop ax						;ax中存放要读取的扇区号
	xor bx, bx
	mov cl, 2					;一次读取2个扇区
	call ReadSector
	pop dx
	add bx, dx
	mov ax, word [es:bx]
	cmp byte [bInHighByte], 0		;看簇号是不是在当前字节的高4位
	jz LABEL_EVEN
	shr ax, 4					;如果是则ax右移4位
LABEL_EVEN:
	and ax, 0xfff
	cmp ax, 0xfff				;如果ax的值为0xfff表示文件结束
	jz	LABEL_FILE_LOADED
	mov cx, ax
	jmp LABEL_GO_ON_LOADING

LABEL_FILE_LOADED:
	call KillMotor		;关闭软驱马达
	mov dh, 1
	call DispStr
	jmp $

ReadSector:
	push bp
	mov bp, sp
	sub sp, 2
	mov byte [bp - 2], cl
	push bx
	mov bl, [BPB_SecPerTrk]			
	div bl						;计算出当前扇区所处的磁道
	inc ah						;除得的商放在al,余数放在ah(al中放的是磁道号,ah中放的是扇区号)
	mov cl, ah
	mov dh, al
	shr al, 1					;磁道号除以2得到磁头号
	mov ch, al
	and ch, 1
	pop bx
	mov dl, [BS_DrvNum]
.GoOnReading:
	mov ah, 2					;读扇区
	mov al, byte [bp - 2]		;要读的扇区数
	int 0x13
	jc .GoOnReading				;读扇区失败则继续读
	add sp, 2
	pop bp, 
	ret

DispStr:
	mov ax, MessageLength
	mul dh
	add ax, BootMessage
	mov bp, ax
	mov ax, ds
	mov es, ax
	mov cx, MessageLength
	mov ax, 0x1301
	mov bx, 0x0007
	mov dl, 0
	add dh, 3
	int 0x10
	ret

KillMotor:
	push dx
	mov dx, 0x3f2
	mov al, 0
	out dx, al
	pop dx
	ret

        从上面的代码可知,相比于Loader.bin的加载,只是多了KillMotor函数,这个函数的作用就是关闭软驱马达,否则软驱的灯会一直亮着。
        因为这里是内核的加载,所以我们需要一个内核,代码如下
[AppleScript] 纯文本查看 复制代码
[section .data]
	Message     db  "In the Kernel"
	StrLen		equ		$ - Message

[section .text]
	global _start

_start:
	mov edx, StrLen
	mov ecx, Message
	mov ebx, 1
	mov eax, 4
	int 0x80
	mov ebx, 0
	mov eax, 1
	int 0x80

        这个代码很简单,就是显示一个字符串,当然了,上面这个加载内核的程序还不能让内核执行,所以这里不会显示这个字符串。我们看内核加载后的执行结果
选区_017.png

评分

参与人数 1i币 +20 收起 理由
管理01 + 20 辛苦了

查看全部评分

回复

使用道具 举报

发表于 2015-11-8 10:32:50 | 显示全部楼层
大神出品
回复 支持 反对

使用道具 举报

发表于 2015-11-8 13:29:06 | 显示全部楼层
学习学习技术,加油!
回复 支持 反对

使用道具 举报

发表于 2015-11-8 21:48:22 | 显示全部楼层
感谢楼主的分享~
回复 支持 反对

使用道具 举报

发表于 2015-11-8 22:09:48 | 显示全部楼层
感谢楼主的分享~
回复 支持 反对

使用道具 举报

发表于 2015-11-9 11:55:46 | 显示全部楼层
回复 支持 反对

使用道具 举报

发表于 2015-11-10 21:39:54 | 显示全部楼层
还是不错的哦,顶了
回复 支持 反对

使用道具 举报

发表于 2015-11-11 20:19:07 | 显示全部楼层
还是不错的哦,顶了
回复 支持 反对

使用道具 举报

发表于 2015-11-11 22:18:01 | 显示全部楼层
支持,看起来不错呢!
回复 支持 反对

使用道具 举报

发表于 2015-11-12 00:07:26 | 显示全部楼层
支持中国红客联盟(ihonker.org)
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

旗下站点

邮箱系统

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2025-3-7 07:31 , Processed in 0.032365 second(s), 18 queries , Gzip On, MemCache On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部