Step0:上期文章更改部分
上期文章有几个错误或者更改的的地方,在这里说一下:
这里改为空着0x00,写的时候想了想,如果使用这样储存文件的方法的话,岂不是一个没用的文件储存系统?
改为:
1个文件夹为14个字节
文件夹ID,是否隐藏(1隐藏 0不隐藏),文件夹的父目录ID(若为根目录的话为0),10个字节的文件名(不足用0x20填充),0x7e(结束符,随便想的)
示例:0x01,0x00,0x00,MyDir1 ,0x7e
改为:
1个文件名称为14个字节
所在文件夹ID(若为根目录的话为0),所在文件储存空间的第几个扇区,是否隐藏(1隐藏 0不隐藏),10个字节的文件名(不足用0x20填充),0x8e(结束符,随便想的)
示例:0x00,0x01,0x00,MyFile1 ,0x8e
这里要注意!所在文件夹ID和所在文件储存空间第几个扇区高位的第一个字节是放在一起的。(后来才发现两位不够用,所以只能先这样)。
Step1:目录树/源码
我们先来看一下这个操作系统文件的目录树:
A:
├─TASK
│ ├─Kernel.sys
没错,做好文件一开机的时候就只有一个TASK和Kernel.sys,Kernel.sys是负责所有的命令的。
本次编译文件有两个,Boot.asm和Kernel.asm,Boot是用来搜索Kernel.asm编译出来的Kernel.sys文件的。
Boot.asm
org 0x7c00
jmp Load
db 0x00 ;可读可写
db 0x01 ;版本1
db 0x00 ;空着
db "Task OS Disk " ;13字节磁盘名称
db "AsmCaiNiao" ;10个字节制造商或开发者名称
times 23 db 0x00 ;空23字节
BootSetCache:
;设置段
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
ret
Load: ;加载区
call BootSetCache
;重置驱动器
mov ah,0
mov dl,0 ;A软驱
int 13h
mov bx,Dirname
mov ah,2
mov al,64 ;测试得来的64个扇区
mov ch,0
mov cl,2
mov dl,0
mov dh,0
int 13h
jc Return
mov si,0
;读取内容,先搜索文件夹
mov si,Dirname+512+3 ;空出前面的512字节和3个字节
FindDir:
mov bx,[si]
mov cx,[si+2]
mov dx,[si+4] ;读
mov di,[si+6]
mov bp,[si+8]
;比较
cmp bx,"TA"
je FindDirNext
FindNextDir:
cmp si,Dirname+512+3
je BootSetStack
BootStack:
pop cx ;将cx出栈
cmp cx,218 ;(4096-1024)/14-1=218个文件夹
je LoadError
add cx,1
push cx
add si,14
jmp FindDir
BootSetStack:
mov cx,1
push cx
jmp BootStack
FindDirNext:
cmp cx,"SK"
jne FindNextDir
cmp dx," "
jne FindNextDir
cmp di," "
jne FindNextDir
cmp bp," "
jne FindNextDir
mov al,[si-3];获取文件夹ID
FindFile:
mov si,Filename+512 ;跳过前面的512字节
mov ah,[si]
mov al,ah
cmp ah,al
je FindFileNext
FindNextFile:
cmp si,Filename+512
je BootSetStack2
BootStack2:
pop cx ;将cx出栈
cmp cx,218 ;(7168-4096)/14-1=218个文件
je LoadError
add cx,1
push cx
add si,14
jmp FindFile
BootSetStack2:
mov cx,1
push cx
jmp BootStack2
FindFileNext:
add si,3
mov bx,[si]
mov cx,[si+2]
mov dx,[si+4] ;读
mov di,[si+6]
mov bp,[si+8]
cmp bx,"Ke"
jne FindNextFile
cmp cx,"rn"
jne FindNextFile
cmp dx,"el"
jne FindNextFile
cmp di,".s"
jne FindNextFile
cmp bp,"ys"
jne FindNextFile
call BootSetCache
;跳转前的准备
mov cl,[si-2]
mov ch,[si-3]
and ch,0fh ;只取个位
mov bx,0x9a00 ;初始化段
mulsq:
cmp cx,1
je JmpKernel
add bx,0x20 ;bx是一个段,给cs
dec cx
jmp mulsq
JmpKernel:
;将bx拷贝到下方跳转的那里,
mov [bootsetcs+1],bx
bootsetcs equ $
jmp 0000:0 ;空着,准备跳
db "00"
;---------------------------------------
Return:
cmp di,5 ;若5次仍然无法读取,抛出错误
je ReadError
add di,1
jmp Load
ReadError:
call BootSetCache
mov ah,3
int 10h
mov ah,13h
mov al,1
mov bp,ReadErrorMsg
mov cx,31
mov bl,0xf4
mov bh,0
int 10h
mov ah,0eh
mov al,0x07
int 10h ;鸣笛一次
jmp CPUEXIT
LoadError:
call BootSetCache
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,LoadErrorMsg
mov cx,45
mov bl,0xf4
mov bh,0
int 10h
mov ah,0eh
mov al,0x07
int 10h ;鸣笛一次
jmp CPUEXIT
ReadErrorMsg db "Unable to read A: All sectors ."
LoadErrorMsg db "Unable to find the file: A:\Task\Kernel.sys ."
CPUEXIT:
HLT
jmp CPUEXIT
times 510-($-$$) db 0x00 ;空510字节
db 0x55,0xaa
times 512 db 0x00 ;再空512字节
;这里是文件夹名称储存区
Dirname:
db 0x01,0x00,0x00,"TASK ",0x8e ;类似于C:\Windows 这里是A:\TASK,01这文件夹的id,00不隐藏,00所在文件夹id。
times 4096-($-$$) db 0xe1
;这里是文件名称储存区
Filename:
db 0x00,0x01,0x01,"Kernel.sys",0x8e ;0不隐藏,001第一个扇区
times 7168-($-$$) db "x"
File:
;Kernel内核部分
Boot.asm中包含两部分:1、引导 2、构建文件夹储存区和文件名储存区。
Kernel.asm代码:
org 0x7c00+7168+512;偏移值
mov ah,0
mov al,2
int 10h
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,Welcomemsg
mov cx,Welcomemsglen
mov bl,0x07
mov bh,0
int 10h
jmp $+Welcomemsglen ;跳到字符串后面
Welcomemsg db "Welcome to Task DOS!",0x0d,0x0a," Make of CSDN AsmCaiNiao.",0x0d,0x0a,"Vesion 1.0",0x0d,0x0a,0x0a,"Init DOS..."
Welcomemsglen equ $-Welcomemsg
;InitDOS
;重读驱动器
mov ah,0
mov dl,0 ;A软驱
int 13h
mov bx,0-0x8000
mov ah,2
mov al,64 ;测试得来的64个扇区
mov ch,0
mov cl,2
mov dl,0
mov dh,0
int 13h
mov ah,02h
mov dl,0
mov dh,5
int 10h ;设置光标
jmp cd2 ;去设置根目录
Disk db 0x0d,0x0a,"A:"
jmpStartdz equ $
Command:
mov ah,0eh
mov al,0x0d
int 10h
mov al,0x0a
int 10h
call showpath
mov ah,0eh
mov al,">"
int 10h
mov si,0
mov cl,121
mov al,0x00
clearinput:
mov [input+si],al
add si,1
dec cl
jnz clearinput
mov si,0
InputKey:
mov ah,0
int 16h ;读键盘
;禁用键盘:
cmp al,0x00
je InputKey
cmp al,0x0a
je InputKey
cmp al,0x07
je InputKey
;特殊处理键盘
cmp al,0x08
je back
cmp al,0x0d
je GetCommand
;命令最多120字节
cmp si,120
je InputKey
mov [input+si],al ;si=命令偏移地址,存到内存后,si偏移指针+1,用来下一次的储存
add si,1
mov ah,0eh
int 10h
jmp InputKey
back:
cmp si,0
je InputKey
sub si,1
mov al,0x00
mov [input+si],al ;将指针-1,空0x00
mov ah,0eh
mov al,0x08
int 10h
mov al,0x00
int 10h
mov al,0x08
int 10h
jmp InputKey
GetCommand:
mov ah,0eh
cmp si,120
je IfCommand
mov al,0x20
mov [input+si],al
IfCommand:
mov al,0x0d
int 10h
mov al,0x0a
int 10h
mov cl,120
;指针归0
mov si,0
mov bp,0
;------------------------------------------------比较命令-------------------------------------------------
;cd
cdIfCommand:
mov ah,[input+si]
mov al,[cd+bp]
cmp al,"$" ;比较到终止符直接跳转至命令
je cdcommand
cmp ah,al
je cdNextIfCommand
jmp clsIfCommand
cdNextIfCommand:
add si,1
add bp,1
jmp cdIfCommand
;cls
clsIfCommand:
mov bp,0
mov si,0
clsifCommand:
mov ah,[input+si]
mov al,[cls+bp]
cmp al,"$"
je clscommand
cmp ah,al
je clsNextIfCommand
jmp dirIfCommand
clsNextIfCommand:
add si,1
add bp,1
jmp clsifCommand
;dir
dirIfCommand:
mov bp,0
mov si,0
dirifCommand:
mov ah,[input+si]
mov al,[dir+bp]
cmp al,"$"
je dircommand
cmp ah,al
je dirNextIfCommand
jmp mkdirIfCommand
dirNextIfCommand:
add si,1
add bp,1
jmp dirifCommand
;mkdir
mkdirIfCommand:
mov bp,0
mov si,0
mkdirifCommand:
mov ah,[input+si]
mov al,[mkdir+bp]
cmp al,