查看: 64316|回复: 915

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

[复制链接]
  • TA的每日心情
    奋斗
    2017-1-16 20:03
  • 签到天数: 116 天

    [LV.6]常住居民II

    发表于 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 辛苦了

    查看全部评分

    回复

    使用道具 举报

  • TA的每日心情
    无聊
    2017-9-11 15:40
  • 签到天数: 425 天

    [LV.9]以坛为家II

    发表于 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 | 显示全部楼层
    还是不错的哦,顶了
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    2019-2-12 22:05
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 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备2021031567号 )

    GMT+8, 2024-12-25 09:49 , Processed in 0.032574 second(s), 21 queries , Gzip On, MemCache On.

    Powered by ihonker.com

    Copyright © 2015-现在.

  • 返回顶部