上几篇我们已经可以通过mbr加载loader文件,并能成功执行loader指令(PS<本章最下面将当前整个开发目录提供了出来,方便大家整个拷贝到本地进行验证)。
下面计划是要扩展我们的loader文件,来进入保护模式的,在保护模式中加载kernel文件,自然想复用我们已经有的filesystem.inc文件。
但检查过这个文件后,发现里面的函数寄存器基本使用的是16位的。且存在修改ds/es的操作。这在实模式下没有关系。但 在进入保护模式就会有问题了。
保护模式下,我们访问32位地址空间,基本要使用32位寄存器;同时在保护模式中ds/es等段寄存器的内容已经发生了变化(后面会说到),不再是实模式下的段物理地址了,而是变成了选择子的内容,如果 代码里面还有对ds/es赋值的,肯定会有问题。
因此需要以代码整改,包括两方面:1. 修改寄存器为32位 2.取消ds/es的修改。
代码如下:
filesystem.inc
;文件系统相关的宏定义
MACRO_DDFS_SYSTEMBLOCK_START_SECTOR_NO EQU 1
MACRO_DDFS_SYSTEMBLOCK_SECTOR_NUM EQU 1
MACRO_DDFS_SECTORBITMAP_START_SECTOR_NO EQU 2
MACRO_DDFS_SECTORBITMAP_SECTOR_NUM EQU 1
MACRO_DDFS_INODEBITMAP_START_SECTOR_NO EQU 3
MACRO_DDFS_INODEBITMAP_SECTOR_NUM EQU 1
MACRO_DDFS_INODEINFO_START_SECTOR_NO EQU 4
MACRO_DDFS_INODEINFO_SECTOR_NUM EQU 512
MACRO_DDFS_FILESECTORLIST_START_SECTOR_NO EQU 516
MACRO_DDFS_FILESECTORLIST_SECTOR_NUM EQU 32
MACRO_DDFS_FILEDATA_START_SECTOR_NO EQU 548
MACRO_DDFS_FILEDATA_SECTOR_NUM EQU 3548
MACRO_DDFS_FILESYSTEM_SIZE_SYSTEMBLOCK EQU 16
MACRO_DDFS_FILESYSTEM_SYSTEMBLOCK_OFFSET_TOTALSECTORNUM EQU 0
MACRO_DDFS_FILESYSTEM_SYSTEMBLOCK_OFFSET_USEDSECTORNUM EQU 4
MACRO_DDFS_FILESYSTEM_SYSTEMBLOCK_OFFSET_TOTALINODENUM EQU 8
MACRO_DDFS_FILESYSTEM_SYSTEMBLOCK_OFFSET_USEDINODENUM EQU 12
MACRO_DDFS_FILESYSTEM_SIZE_INODEINFO EQU 64
MACRO_DDFS_FILESYSTEM_INODEINFO_OFFSET_FILENAME EQU 0
MACRO_DDFS_FILESYSTEM_INODEINFO_OFFSET_FILESIZE EQU 32
MACRO_DDFS_FILESYSTEM_INODEINFO_OFFSET_FILESECTORNUM EQU 36
MACRO_DDFS_FILESYSTEM_INODEINFO_OFFSET_FILESTARTSECTOR EQU 40
MACRO_DDFS_FILESYSTEM_SIZE_FILESECTORLIST EQU 8
MACRO_DDFS_FILESYSTEM_FILESECTORLIST_OFFSET_ISNEXTVALID EQU 0
MACRO_DDFS_FILESYSTEM_FILESECTORLIST_OFFSET_NEXTSECTOR EQU 4
MACRO_DDFS_FILESYSTEM_INODE_NUM EQU 4096
globalSectorSpace: times 512 db 0
;-------------------------------------------------------------
;函数名:getDiskDataFromSectors(起始扇区号, 扇区数目, 起始内存地址)
;函数说明:从指定起始扇区处连续加载指定扇区数目的数据到指定的内存起始位置处
;函数参数:
; 参数说明 参数位置 参数大小
; 起始扇区号, bp+4 2字节
; 扇区数目, bp+6 2字节
; 起始内存地址: bp+8 4字节
;返回值:
; 无
;-------------------------------------------------------------
getDiskDataFromSectors:
push ebp
mov ebp, esp
pushad
;加载的内存起始地址
mov edi, [ebp+10]
;要读取的扇区数目
mov ax, [ebp+8]
;起始扇区号
mov si, [ebp+6]
mov dx,0x1f2
out dx,al ;读取的扇区数
inc dx ;0x1f3
mov ax,si
out dx,al ;LBA地址7~0
inc dx ;0x1f4
mov al,ah
out dx,al ;LBA地址15~8
xor ax, ax
inc dx ;0x1f5
out dx,al ;LBA地址23~16
inc dx ;0x1f6
mov al,0xe0 ;LBA28模式,主盘
out dx,al
inc dx ;0x1f7
mov al,0x20 ;读命令
out dx,al
.waits:
in al,dx
and al,0x88
cmp al,0x08
jnz .waits ;不忙,且硬盘已准备好数据传输
;计算要循环读取的字节数目,由于一次读取是2个字节,因此总字节除以2
mov ax, [ebp+8]
mov bx, 512
mul bx
mov bx, 2
div bx
mov cx, ax
mov dx,0x1f0
.readw:
in ax,dx
mov [edi],ax
add edi, 2
loop .readw
popad
pop ebp
ret
;-------------------------------------------------------------
;函数名:getSystemBlockData(buf)
;函数说明:获取文件系统块,保存buf中
;函数参数:
; 参数说明 参数位置 参数大小
; buf bp+4 4字节
;返回值:
; 无
;补充说明:
;-------------------------------------------------------------
getSystemBlockData:
push ebp
mov ebp, esp
pushad
mov eax, [ebp+6]
push eax
mov ax, MACRO_DDFS_SYSTEMBLOCK_SECTOR_NUM
push ax
mov ax, MACRO_DDFS_SYSTEMBLOCK_START_SECTOR_NO
push ax
call getDiskDataFromSectors
pop ax
pop ax
pop eax
popad
pop ebp
ret
;-------------------------------------------------------------
;函数名:getInodeBitMapData(buf)
;函数说明:获取inodebitmap,保存到buf中
;函数参数:
; 参数说明 参数位置 参数大小
; buf bp+4 4字节
;返回值:
; 无
;补充说明:
;-------------------------------------------------------------
getInodeBitMapData:
push ebp
mov ebp, esp
pushad
mov eax, [ebp+6]
push eax
mov ax, MACRO_DDFS_INODEBITMAP_SECTOR_NUM
push ax
mov ax, MACRO_DDFS_INODEBITMAP_START_SECTOR_NO
push ax
call getDiskDataFromSectors
pop ax
pop ax
pop eax
popad
pop ebp
ret
;-------------------------------------------------------------
;函数名:getInodeInfoByInodeIndex(inodeindex, buf)
;函数说明:通过inode索引获取对应的inodeinfo
;函数参数:
; 参数说明 参数位置 参数大小
; inodeindex bp+4 2
; buf bp+6 4字节
;返回值:
; eax: 0:未使用 1:已经使用
;补充说明:
;-------------------------------------------------------------
getInodeInfoByInodeIndex:
push ebp
mov ebp, esp
pushad
mov ax, [ebp+6]
xor edx, edx
mov bx, MACRO_DDFS_FILESYSTEM_SIZE_INODEINFO
mul bx
;除以512后,ax保存扇区偏移,dx保存扇区内偏移
mov bx, 512
div bx
add ax, MACRO_DDFS_INODEINFO_START_SECTOR_NO
mov ebx, globalSectorSpace
push ebx
mov bx, 1
push bx
mov bx, ax
push bx
call getDiskDataFromSectors
pop bx
pop bx
pop ebx
;将64字节内容拷贝到用户区
xor esi, esi
mov esi, globalSectorSpace
add esi, edx
xor edi, edi
mov edi, [ebp+8]
mov cx, MACRO_DDFS_FILESYSTEM_SIZE_INODEINFO
cld
rep movsb
popad
pop ebp
ret
;-------------------------------------------------------------
;函数名:getFileSectorListBySector(sector, buf)
;函数说明:通过Secto索引获取对应的filesectorlist信息
;函数参数:
; 参数说明 参数位置 参数大小
; sector bp+4 2
; buf bp+6 4字节
;返回值:
; eax: 0:未使用 1:已经使用
;补充说明:
;-------------------------------------------------------------
getFileSectorListBySector:
push ebp
mov ebp, esp
pushad
mov ax, [ebp+6]
xor edx,edx
mov bx, MACRO_DDFS_FILESYSTEM_SIZE_FILESECTORLIST
mul bx
mov bx,512
div bx
mov ebx, globalSectorSpace
push ebx
mov bx, 1
push bx
mov bx, MACRO_DDFS_FILESECTORLIST_START_SECTOR_NO
add bx, ax
push bx
call getDiskDataFromSectors
pop bx
pop bx
pop ebx
;将8字节内容拷贝到用户区
mov esi, globalSectorSpace
add esi, edx
mov edi, [ebp+8]
mov cx, MACRO_DDFS_FILESYSTEM_SIZE_FILESECTORLIST
cld
rep movsb
popad
pop ebp
ret
;-------------------------------------------------------------
;函数名:checkFileNameIsSame(dstFileName, srcFileName, FileLen, outBuf)
;函数说明:比较指定长度的源目的文件名是否相同
;函数参数:
; 参数说明 参数位置 参数大小
; dstFileName bp+4 4字节
; srcFileName bp+8 4字节
; dstFileName bp+12 2字节
; outBuf bp+14 4字节
;返回值:
; outBuf: 0:不相同 1:相同
;补充说明:
;-------------------------------------------------------------
checkFileNameIsSame:
push ebp
mov ebp, esp
pushad
mov esi, [ebp+6]
mov edi, [ebp+10]
mov cx, [ebp+14]
cld
repz cmpsb
cmp cx, 0
jz file_name_same
mov esi, [ebp+16]
mov word [esi], 0
popad
pop ebp
ret
file_name_same:
mov esi, [ebp+16]
mov word [esi], 1
popad
pop ebp
ret
;-------------------------------------------------------------
;函数名:checkFileNameIsSame(bitIndex, bitBuffer, outBuf)
;函数说明:比较指定长度的源目的文件名是否相同
;函数参数:
; 参数说明 参数位置 参数大小
; bitIndex bp+4 2字节
; bitBuffer bp+6 4字节
; outBuf bp+10 4字节
;返回值:
; outBuf: 0:不相同 1:相同
;补充说明:
;-------------------------------------------------------------
checkBitIsSet:
push ebp
mov ebp, esp
pushad
xor eax, eax
mov ax, [ebp+6]
mov ebx, [ebp+8]
mov ecx, [ebp+12]
push ebx
xor dx, dx
mov bx, 8
div bx
pop ebx
add ebx, eax
mov esi, ebx
bt [esi], dx
jc bit_is_set
mov esi, ecx
mov word [esi], 0
popad
pop ebp
ret
bit_is_set:
mov esi, ecx
mov word [esi], 1
popad
pop ebp
ret
最明显的变化是bp变成的ebp, 比如getDiskDataFromSectors,左侧是修改前,右侧是修改后的;还要注意的是用了32位后,实际的入栈参数偏移已经发生了变化 。
这里我们还多做了个文件,在写入boot后,先额外的写个其它文件(比如我们直接把boot.asm文件写入磁盘中),让它占用Inode0,然后再写入Loader.bin,通过这种方式来检查我们的查找loader.bin是否正确。如果 正确,它要显示 出Loader运行的提示。
我们把前面 的操作再重复一下, 操作按照如下步骤进行:
1. 先格式化我们的磁盘,并安装文件系统 。
使用我们之前编写的文件系统 初始化工具mkddfs,(D_D系统构建-文件写入方法: http://blog.csdn.net/b06030927/article/details/73050529)
2.编译并安装boot,这两个动作已经集成到makefile中。
3.在编译loader.bin之前,先安装个其它文件,我们选择了boot.asm,检查下inode分配是否正确,及后面写入loader.bin会不会有问题
4. 调用readddfs工具(同mkddfs), 查看当前文件系统 的应用情况,可以看到写入boot.asm后,可以看到它占用了一个Inode.同时能持到这个boot.asm文件大小,及占用的扇区情况。
5.此时 再编译并写入loader.bin,
6.检查下此时 的文件系统应用情况,占用两个inode,文件大小与实际 的大小一致。
7.最关键的一步到了,现在是检验我们的系统 能否正常加载 loader.bin了。运行bochs
很明显,它正确的找到了我们的Loader.bin,修改后的文件能正常生效,
这样,在下面的保护系统章节里面,我们还 能继续借用这个filessytem.inc函数,节省点开发时间。
PS: 另外,之前 一直没有找到能把整个开发文件目录打包并放到csdn上的方法,这里面把它压缩并放到百度网盘里面,下面是链接,不需要密码,大家随意取用。
http://pan.baidu.com/s/1o8iGp5K
这里面包含我使用的整个开发文件,大家下载后,到linux上解压开来,应该就可以使用。
下面开始我会改造当前的loader,让其工作在保护 模式下,跳出1M空间的限制,自由切换4G空间。
近期项目又紧张,更新会慢,但不会中断。。。加油。