概述
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:TaskKernel.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,"$"
je mkdircommand
cmp ah,al
je mkdirNextIfCommand
jmp typeIfCommand
mkdirNextIfCommand:
add si,1
add bp,1
jmp mkdirifCommand
;type
typeIfCommand:
mov bp,0
mov si,0
typeifCommand:
mov ah,[input+si]
mov al,[type+bp]
cmp al,"$"
je typecommand
cmp ah,al
je typeNextIfCommand
jmp delIfCommand
typeNextIfCommand:
add si,1
add bp,1
jmp typeifCommand
;del
delIfCommand:
mov bp,0
mov si,0
delifCommand:
mov ah,[input+si]
mov al,[del+bp]
cmp al,"$"
je delcommand
cmp ah,al
je delNextIfCommand
jmp rdIfCommand
delNextIfCommand:
add si,1
add bp,1
jmp delifCommand
;rd
rdIfCommand:
mov bp,0
mov si,0
rdifCommand:
mov ah,[input+si]
mov al,[rd+bp]
cmp al,"$"
je rdcommand
cmp ah,al
je rdNextIfCommand
jmp writeIfCommand
rdNextIfCommand:
add si,1
add bp,1
jmp rdifCommand
;write
writeIfCommand:
mov bp,0
mov si,0
writeifCommand:
mov ah,[input+si]
mov al,[write+bp]
cmp al,"$"
je writecommand
cmp ah,al
je writeNextIfCommand
jmp Commandfin
writeNextIfCommand:
add si,1
add bp,1
jmp writeifCommand
;--------------------------------------------------------------------------------------------------------
Commandfin:
jmp IfBadCommand
input times 120 db 0x00 ;定义一个地址,空着,里面保存输入的内容
db 0x00 ;空一字节用来被填充0x20
;-------------命令定义区--------------
cd db "cd $"
cls db "cls $"
dir db "dir $"
mkdir db "mkdir $"
type db "type $"
del db "del $"
rd db "rd $"
write db "write $"
;-------------------------------------
IfBadCommand:
mov ah,[input+si]
cmp ah,0x00
je SubBad
cmp ah,0x20
je SubBad
jmp BadCommand
SubBad:
dec cl
jnz IfBadCommand
jmp Command
BadCommand:
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,BadCommandmsg
mov cx,13
mov bl,0x07
mov bh,0
int 10h
mov si,0
mov cl,120
printBadCommand:
mov ah,0eh
mov al,[input+si]
int 10h
add si,1
dec cl
jnz printBadCommand
jmp Command
BadCommandmsg db "Bad Command: "
;---------------------------------cd命令------------------------------------------------
cdcommand:
;cd 有5种命令。直接填写cd,打印当前目录;cd+目录,进入该目录;cd 或 cd /,进入根目录;cd ..;返回上一级;cd .>+文件名,创建文件
mov cl,120
mov al,[input+3]
cmp al,0x00
je cd1
cmp ah,""
je cd2
cmp ah,"/"
je cd2
mov ax,[input+3]
cmp ax,".."
je cd3
cmp ax,".>"
je cd4
;通过现在目录的id,遍历目录,若检测到有目录所在id和当前目录的id一样,则进行比较
mov cl,218 ;218个文件夹
mov si,0-0x8000+0x200+2 ;设置指针
finddir: ;开始遍历目录
pop ax
push ax
mov ah,[si]
cmp ah,al ;比较到一样的id比较名称
je comdir
add si,14 ;否则指针+14
dec cl
jnz finddir
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,DirNotfind
mov cx,12
mov bl,0x07
mov bh,0
int 10h
add dl,13
mov ah,13h
mov al,1
mov bp,input+3
mov cx,117
mov bl,0x07
mov bh,0
int 10h
jmp Command
DirNotfind db "No find dir:"
comsetah0x20:
mov ah,0x20
jmp comsetah0x20fin
comdir:
mov di,si ;备份si
mov bp,3 ;input指针归0
add si,1 ;si加1,指向文件夹名称的第一个字符
mov ch,9
comcmpdir:
mov ah,[input+bp]
cmp ah,0x00
je comsetah0x20
comsetah0x20fin:
mov al,[si]
cmp ah,al
jne finnextdir
comnextfin:
add si,1
add bp,1
dec ch
jnz comcmpdir
;确认一样后,获取文件夹id
pop ax
mov ah,0
mov al,[di-2]
push ax
mov si,0 ;指针归0
writepath:
mov ah,[path+si]
cmp ah,0xee
je writepathcode
add si,1
jmp writepath
writepathcode:
mov [path+si],al
jmp Command
findnext:
add si,1
add bp,1
dec ch
jmp comnextfin
finnextdir:
dec cl
mov si,di
add si,14
jmp finddir
cdCommandDisk db "A:"
path times 218 db 0xee ;218个文件夹
db 0xee;预留
cd1:
call showpath
jmp Command
cd2:
pop ax
mov ax,0x0000 ;设置根目录
push ax
mov si,0
mov cl,218
mov al,0xee
clearpath: ;清空path
mov [path+si],al
add si,1
dec cl
jnz clearpath
cd3:
;通过获取当前文件夹id,在文件夹中搜索该文件,之后获取所在文件夹id。
pop ax
push ax
cmp al,0x00 ;al为0x00就是在根目录,直接返回comand
je Command
mov si,0-0x8000+0x200;设置指针
mov cl,218 ;218个文件夹
finddircode:
mov ah,[si]
cmp ah,al
je getlastdircode
add si,14
jmp finddircode
getlastdircode:
pop ax
add si,2
mov al,[si]
mov ah,0
push ax
mov si,0
writepath2:
mov al,[path+si]
cmp al,0xee
je writepath2code
add si,1
jmp writepath2
writepath2code:
sub si,1
mov al,0xee
mov [path+si],al
jmp Command
showpath:
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,cdCommandDisk
mov cx,3
mov bl,0x07
mov bh,0
int 10h
pop ax
push ax
cmp al,0x00
je dirfin
;通过获取path来显示目录
mov si,0xffff ;指针
cdshow:
mov bp,0-0x8000+0x200 ;初始化指针
add si,1
mov al,[path+si]
cmp al,0xee
jne cdshowfinddir
jmp dirfin
cdshowfinddir:
mov ah,[bp]
cmp al,ah
je cdshowpath
add bp,14
jmp cdshowfinddir
cdshowpath:
mov ah,03h
int 10h
mov ah,13h
mov al,1
add bp,3
mov cx,10
mov bl,0x07
mov bh,0
int 10h
mov ah,03h
int 10h
set_cursor:
mov ah,02h
sub dl,1
int 10h
mov ah,08h
int 10h
cmp al,0x20
je set_cursor
mov ah,02h
add dl,1
int 10h
mov ah,0eh
mov al,''
int 10h
jmp cdshow
dirfin:
ret
cd4:
mov al,[input+15]
cmp al,0x00
je makefile
cmp al,0x20
je makefile
filenametobig:
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,filenametobigmsg
mov cx,36
mov bl,0x07
mov bh,0
int 10h
jmp Command
filenametobigmsg db "The file name can be up to 10 bytes."
setinput:
mov al,[input+16]
cmp al,0x00
jne filenametobig
mov al,0x20
mov [input+si],al
inc si
inc ch
dec cl
jnz setinput0to20
jmp setinput0to20fin
makefile:
;首先,需要输入中的将0x00替换为0x20
mov cl,10 ;字节文件名
mov si,5 ;指针初始化
mov ch,0
setinput0to20:
mov al,[input+si]
cmp al,0x00
je setinput
cmp al,0x20
je setinput ;用于ch+1
inc si
dec cl
jnz setinput0to20
setinput0to20fin:
cmp ch,10
je NoEntryfilename
mov ah,03h
int 10h
mov bp,dx
mov cl,218 ;218个文件
mov si,0-0x8000+0x200+0xc00+3 ;初始化指针
mov di,input+5
makefilefindfile:
mov ax,[si]
mov bx,[di]
cmp ax,bx
jne makefindnextfile
mov ax,[si+2]
mov bx,[di+2]
cmp ax,bx
jne makefindnextfile
mov ax,[si+4]
mov bx,[di+4]
cmp ax,bx
jne makefindnextfile
mov ax,[si+6]
mov bx,[di+6]
cmp ax,bx
jne makefindnextfile
mov ax,[si+8]
mov bx,[di+8]
cmp ax,bx
jne makefindnextfile
mov di,bp
;之后比较文件夹id
pop ax
push ax
mov ah,[si-1]
cmp ah,al
jne makenewfile
;说明已经在该目录下有该文件了,抛出错误
mov ah,13h
mov al,1
mov bp,filehavemsg
mov cx,42
mov bl,0x07
mov bh,0
mov dx,di
int 10h
jmp Command
filehavemsg db "The file already exists in this directory."
makenewfile:
mov bp,dx
;先获取当前id,之后在文件名称储存位置创建一个文件名,之后遍历储存目录
pop ax
push ax
mov si,0-0x8000+0x200+0xc00+13 ;初始化指针
mov cl,218 ;218个文件夹
makenewfilefindfile: ;遍历文件以获取储存空间,若218个文件仍然没有找到可储存的地方,说明储存空间已经满了,抛出异常
mov al,[si]
cmp al,"x"
je makefilename
add si,1
dec cl
jnz makenewfilefindfile
;抛出异常
mov dx,bp
mov ah,13h
mov al,1
mov bp,filetobigmsg
mov cx,36
mov bl,0x07
mov bh,0
int 10h
jmp Command
filetobigmsg db 0x0d,"There can be only 218 files at most."
makefilename:
;现在si指向创建新文件名的地址
;先要在文件区申请创建一个储存位置,所以要遍历文件的储存扇区
;一个段是16字节
mov ax,0x09a0 ;文件储存空间在09a0h段
mov ds,ax
mov cx,0
mov bp,973*2 ;973kb的储存区,2扇区=1kb。
makefilefindMemory:
mov al,[0]
cmp al,0xe2 ;说明有空扇区
je makenewfilewrite
mov ax,ds
add ax,32 ;一个段16字节,512/16=32个段。
mov ds,ax
add cx,1
dec bp
jnz makefilefindMemory
;说明储存空间又又又又满了,抛出错误
mov ax,0
mov ds,ax ;ds归0
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,floppymemoryfullmsg
mov cx,34
mov bl,0x07
mov bh,0
int 10h
jmp Command
floppymemoryfullmsg db "Floppy disk storage space is full."
makenewfilewrite:
mov di,cx ;备份cx
;先要在当前ds写入结束符
mov cl,0xb8
mov [0],cl
mov cx,0x0000
mov [1],cx
mov cx,0x88cd
mov [3],cx
;写硬盘
mov bx,0x7c00+7168+512 ;文件起始段
mov ah,03h
mov al,51 ;写完剩下的扇区
mov ch,0
mov cl,15 ;15扇区开始
mov dl,0
mov dh,0
int 13h
;特别重要!!!要将ds置回0!不然乱读段导致系统崩溃!
mov ax,0
mov ds,ax
;写文件名
;先写入内存
mov cx,di
and ch,0fh ;只取个位
mov [si],ch
mov [si+1],cl
pop ax
push ax
mov [si+2],al
mov cl,10
add si,3
mov bp,5
makenewfilewritefilename:
mov ah,[input+bp]
mov [si],ah
add si,1
add bp,1
dec cl
jnz makenewfilewritefilename
mov ah,0x8e
mov [si],ah ;结束符
mov bx,0-0x8000+7168-0xe00
mov ah,03h
mov al,6 ;写6个扇区
mov ch,0
mov cl,9 ;9扇区开始
mov dl,0
mov dh,0
int 13h
mov ah,0
mov al,2
int 10h
jmp Command
makefindnextfile:
cmp cl,0
je makenewfile
dec cl
add si,14
mov di,input+5
jmp makefilefindfile
NoEntryfilename:
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,NoEntryfilenamemsg
mov cx,26
mov bl,0x07
mov bh,0
int 10h
jmp Command
NoEntryfilenamemsg db "You didn't type file name."
;---------------------------------------------------------------
;cls命令
clscommand:
mov ah,0
mov al,2
int 10h
jmp Command
;---------------------------------------------------------------
;------------------------------------------------------------------dir命令-----------------------------------------------------------------------------
;dir需要先获取当前文件夹id,之后遍历所有文件和文件夹。
dircommand:
mov ah,3
int 10h
mov ah,13h
mov al,1
mov bp,Nowdirmsg
mov cx,9
mov bl,0x07
mov bh,0
int 10h
call showpath
;开始打印文件夹
mov si,0-0x8000+0x200 ;初始化指针
mov ah,0eh
mov al,0x0d
int 10h
mov al,0x0a
int 10h
mov al,0x0a
int 10h
Dirprint:
pop ax
push ax
mov ah,[si+2]
cmp al,ah
je dirprint
add si,14
dec cl
jnz Dirprint
Fileprintinit:
mov si,0-0x8000+0x200+0xc00;初始化指针
mov cl,218
Fileprint:
pop ax
push ax
mov ah,[si+2]
cmp al,ah
je fileprint
add si,14
dec cl
jnz Fileprint
jmp Command
dirprint:
mov ah,03h
int 10h
mov bp,si
add bp,3
mov ah,13h
mov al,1
mov cx,10
mov bl,0x07
mov bh,0
int 10h
mov ah,03h
int 10h
mov dl,15
mov ah,02h
int 10h
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,Diratt
mov cx,5
mov bl,0x07
mov bh,0
int 10h
mov ah,0eh
mov al,0x0d
int 10h
mov al,0x0a
int 10h
add si,14
dec cl
jnz Dirprint
jmp Fileprintinit
fileprint:
mov ah,03h
int 10h
mov bp,si
add bp,3
mov ah,13h
mov al,1
mov cx,10
mov bl,0x07
mov bh,0
int 10h
mov ah,03h
int 10h
mov dl,15
mov ah,02h
int 10h
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,Fileatt
mov cx,6
mov bl,0x07
mov bh,0
int 10h
mov ah,0eh
mov al,0x0d
int 10h
mov al,0x0a
int 10h
add si,14
dec cl
jnz Fileprint
jmp Command
Nowdirmsg db "Now Dir: "
Diratt db "<dir>"
Fileatt db "<file>"
;------------------------------------------------------------------------------------------------------------------------------------------------------
;---------------------------------------------------mkdir命令----------------------------------------------------------------------
mkdircommand:
mov al,[input+17]
cmp al,0x00
jne mkdirnametobig
mov cl,10
mov si,6 ;指针初始化
mov ch,0
mkdirset0to20:
mov al,[input+si]
cmp al,0x00
je mkdirset
cmp al,0x20
je mkdirset
inc si
dec cl
jnz mkdirset0to20
jmp mkdirwritemem
mkdirset:
mov al,0x20
mov [input+si],al
add si,1
add ch,1
dec cl
jnz mkdirset0to20
jmp mkdirwritemem
mkdirwritemem:
cmp ch,10
je mkdirnoentrydir
mov si,0-0x8000+0x200+3
mov cl,218
mov ah,03h
int 10h
mov di,dx
mkdirfindcmfile: ;遍历218个目录看是否有重名的目录
mov ax,[si]
mov bx,[input+6]
cmp ax,bx
jne mkdirfindnextdir
mov ax,[si+2]
mov bx,[input+6+2]
cmp ax,bx
jne mkdirfindnextdir
mov ax,[si+4]
mov bx,[input+6+4]
cmp ax,bx
jne mkdirfindnextdir
mov ax,[si+6]
mov bx,[input+6+6]
cmp ax,bx
jne mkdirfindnextdir
mov ax,[si+8]
mov bx,[input+6+8]
cmp ax,bx
jne mkdirfindnextdir
;还要比较当前目录id
pop ax
push ax
mov ah,[si-1]
cmp al,ah
jne mkdirfindnextdir
;说明有同名文件夹,抛出异常
mov dx,di
mov ah,13h
mov al,1
mov bp,mkdircmmsg
mov cx,22
mov bl,0x07
mov bh,0
int 10h
jmp Command
mkdirfindnextdir:
add si,14
dec cl
jnz mkdirfindcmfile
;遍历目录id,若检测到空储存目录
mov si,0-0x8000+0x200
mov cl,218
mov ch,1
mkdirfinddir:
mov al,[si]
cmp al,0xe1
je mkdirdir
add si,14
inc ch
dec cl
jnz mkdirfinddir
;如果检测了218个文件夹后,仍然没找到文件夹空着的储存空间,说明文件夹已经满了,抛出错误。
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,mkdirerrormsg
mov cx,36
mov bl,0x07
mov bh,0
int 10h
jmp Command
mkdirnoentrydir:
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,mkdirnoentrymsg
mov cx,36
mov bl,0x07
mov bh,0
int 10h
jmp Command
mkdirnametobig:
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,mkdirnametobigmsg
mov cx,34
mov bl,0x07
mov bh,0
int 10h
jmp Command
mkdirdir:
;先写入内存
mov [si],ch ;写入文件id
mov al,0x00
mov [si+1],al ;0x00不隐藏
pop ax
push ax
mov [si+2],al ;所在文件夹id
mov cl,10
mov bp,6
add si,3
mkdirwritememwhile:
mov al,[input+bp]
mov [si],al
add si,1
add bp,1
dec cl
jnz mkdirwritememwhile
mov al,0x8e
mov [si],al
;写入硬盘
mov bx,0-0x8000+0x200
mov ah,03h
mov al,6 ;写6个扇区
mov ch,0
mov cl,3 ;3扇区开始
mov dl,0
mov dh,0
int 13h
mov ah,02h
mov dx,di
int 10h
jmp Command
mkdirerrormsg db "Only 218 files can be saved at most."
mkdirnoentrymsg db "You You did not enter a folder name."
mkdirnametobigmsg db "The maximum file name is 10 bytes."
mkdircmmsg db "Folder already exists."
;--------------------------------------------------------------------------------------------------------------------------------------------------
;----------------------------------------------------------type命令--------------------------------------------------------------------------------
;通过获取当前文件id,寻找文件,之后将ds指向段,最后读出内容即可。
typecommand:
;先比较文件名是否超过10字节
mov al,[input+16]
cmp al,0x00
jne typefilenamebig
;将0x00转换成0x20
mov bp,5 ;指针初始化
mov cl,0
mov ch,10
typeset0to20:
mov al,[input+bp]
cmp al,0x00
je typesjset0to20
cmp al,0x20
je typesjset0to20
add bp,1
dec ch
jnz typeset0to20
jmp typefindfile
typesjset0to20:
mov al,0x20
mov [input+bp],al
add bp,1
add cl,1
dec ch
jnz typeset0to20
jmp typefindfile
typefilenamebig:
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,typefilenamebigmsg
mov cx,39
mov bl,0x07
mov bh,0
int 10h
jmp Command
typenoentryfilename:
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,typenoentryfilenamemsg
mov cx,30
mov bl,0x07
mov bh,0
int 10h
jmp Command
typefilenamebigmsg db "No files with more than 10 bytes exist."
typenoentryfilenamemsg db "You did not enter a file name."
typefindfile:
cmp cl,10
je typenoentryfilename
;开始寻找文件
pop ax
push ax
mov si,0-0x8000+4096-512+3
mov bl,218 ;218个文件
typefindfilerun:
mov cx,[si]
cmp cx,[input+5]
jne typefindnextfile
mov cx,[si+2]
cmp cx,[input+7]
jne typefindnextfile
mov cx,[si+4]
cmp cx,[input+9]
jne typefindnextfile
mov cx,[si+6]
cmp cx,[input+11]
jne typefindnextfile
mov cx,[si+8]
cmp cx,[input+13]
jne typefindnextfile
;还需要比较文件id
mov ah,[si-1]
cmp al,ah
jne typefindnextfile
;确认有文件之后,ds指向文件段,开读
mov ax,[si-3]
and ah,0fh ;ax高位十位置0
mov cl,al
mov al,ah
mov ah,cl ;高低位互换
;提前初始化指针si
mov si,0
;初始化ds
mov bx,0x09a0
mov ds,bx
;ax=1直接去读
cmp ax,1
je typeread
;一段是16字节,512/16=32段
typedsset:
add bx,0x20
dec ax
jnz typedsset
mov ds,bx
jmp typeread
typeread:
mov ah,0eh
mov al,[si]
cmp al,0xb8 ;说明文件有可能已经读完
je typeiffin
typeshow:
int 10h;否则中断显示
add si,1
cmp si,16 ;一个段
je typereadaddds
jmp typeread
typereadaddds:
add bx,1
mov ds,bx
mov si,0
jmp typeread
typefindnextfile:
add si,14
dec bl
jnz typefindfilerun
;说明不存在该文件,抛出错误
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,typenofilemsg
mov cx,16
mov bl,0x07
mov bh,0
int 10h
mov cl,10
mov si,5
typeshowfile:
mov ah,0eh
mov al,[input+si]
int 10h
add si,1
dec cl
jnz typeshowfile
jmp Command
typenofilemsg db "File not found: "
typeiffin:
mov cx,[si+1]
cmp cx,0x0000
jne typeshow
mov cx,[si+3]
cmp cx,0x88cd
jne typeshow
jmp typefin
typefin:
mov bx,0
mov ds,bx ;ds归0
jmp Command
;----------------------------------------------------------------------------------------------------------------------------
;-----------------------------------------------------------del命令----------------------------------------------------------
delcommand:
mov al,[input+15]
cmp al,0x00
jne delentryfiletobig
;还是先将0x00转成0x20
mov cl,10
mov si,4
mov bl,0
delset0to20:
mov al,[input+si]
cmp al,0x00
je delset0to20run
cmp al,0x20
je delset0to20run
add si,1
dec cl
jnz delset0to20
jmp delfindfile
delset0to20run:
mov al,0x20
mov [input+si],al
add bl,1
add si,1
dec cl
jnz delset0to20
jmp delfindfile
delentryfiletobig:
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,delentryfiletobigmsg
mov cx,32
mov bl,0x07
mov bh,0
int 10h
jmp Command
delnoetryfile:
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,delnoetryfilemsg
mov cx,30
mov bl,0x07
mov bh,0
int 10h
jmp Command
delentryfiletobigmsg db "No file is longer than 10 bytes."
delnoetryfilemsg db "You did not enter a file name."
delfindfile:
cmp bl,10
je delnoetryfile
;首先获取当前的文件夹id,搜索是否有这个文件
pop ax
push ax
mov bl,218
;初始化指针
mov si,0-0x8000+4096-512+3
delfindfilerun:
mov cx,[input+4]
cmp cx,[si]
jne delfindnextfile
mov cx,[input+6]
cmp cx,[si+2]
jne delfindnextfile
mov cx,[input+8]
cmp cx,[si+4]
jne delfindnextfile
mov cx,[input+10]
cmp cx,[si+6]
jne delfindnextfile
mov cx,[input+12]
cmp cx,[si+8]
jne delfindnextfile
mov ah,[si-1]
cmp ah,al
jne delfindnextfile
jmp delfile
delfindnextfile:
add si,14
dec bl
jnz delfindfilerun
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,delnofindfilemsg
mov cx,15
mov bl,0x07
mov bh,0
int 10h
mov si,4
mov cl,10
delshowfile:
mov ah,0eh
mov al,[input+si]
int 10h
add si,1
dec cl
jnz delshowfile
jmp Command
delnofindfilemsg db "File not found:"
delfile:
;先将储存在文件名储存区的抹掉,之后再将在文件储存区的内容抹掉
sub si,3
mov bp,[si] ;保存所在扇区
mov cl,14
mov ah,"x"
delremovename:
mov [si],ah
add si,1
dec cl
jnz delremovename
;写入扇区
mov bx,0-0x8000+7168-0xe00
mov ah,03h
mov al,6 ;写6个扇区
mov ch,0
mov cl,9 ;9扇区开始
mov dl,0
mov dh,0
int 13h
mov si,0;提前初始化指针si
;现在要抹掉文件内容
mov ax,09a0h
mov ds,ax ;初始化段
;高低位互换
mov ax,bp
mov cl,al
mov al,ah
mov ah,cl
mov bp,ax
mov bx,ds
cmp bp,1 ;1直接去抹除文件
je delremovefile
mov ax,ds
deldsset:
add ax,0x20
dec bp
jnz deldsset
mov ds,ax
delremovefile:
;现在可以开始抹除文件了
mov al,[si]
cmp al,0xb8 ;有可能抹除完了
je delremovefileiffin
delremovebyte:
mov al,0xe2
mov [si],al
add si,1
cmp si,16;一段
je deladdds
jmp delremovefile
delremovefileiffin:
mov cx,[si+1]
cmp cx,0x0000
jne delremovebyte
mov cx,[si+3]
cmp cx,0x88cd
jne delremovebyte
;说明抹除完成,把5个字节都抹除再写入硬盘就可以
mov al,0xe2
mov ah,5
delremovew:
mov [si],al
add si,1
dec ah
jnz delremovew
;写硬盘
mov bx,0x7c00+7168+512 ;文件起始段
mov ah,03h
mov al,51 ;写完剩下的扇区
mov ch,0
mov cl,15 ;15扇区开始
mov dl,0
mov dh,0
int 13h
mov bx,0
mov ds,bx
jmp Command
deladdds:
add bx,0001
mov ds,bx
mov si,0
jmp delremovefile
;----------------------------------------------------------------------------------------------------------------------------
;------------------------------------------------------------rd命令----------------------------------------------------------
;删除目录必须要空目录才可以,否则抛出错误
rdcommand:
;查看文件名是否大于10字节
mov al,[input+14]
cmp al,0x00
jne rdentryfiletobig
;将0x00转换成0x20
mov cl,10
mov si,3
mov bl,0
rdset0to20:
mov al,[input+si]
cmp al,0x00
je rdset0to20run
cmp al,0x20
je rdset0to20run
add si,1
dec cl
jnz rdset0to20
jmp rddir
rdset0to20run:
mov al,0x20
mov [input+si],al
add bl,1
add si,1
dec cl
jnz rdset0to20
jmp rddir
rdentryfiletobig:
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,rdentryfiletobigmsg
mov cx,34
mov bl,0x07
mov bh,0
int 10h
jmp Command
rdnoentryfilename:
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,rdnoentryfilenamemsg
mov cx,32
mov bl,0x07
mov bh,0
int 10h
jmp Command
rdentryfiletobigmsg db "No folder is larger than 10 bytes."
rdnoentryfilenamemsg db "You did not enter a folder name."
rddir:
cmp bl,10
je rdnoentryfilename
;搜索文件夹
mov si,0-0x8000+0x200+3
mov bl,218
pop ax
push ax
rdfinddir:
mov cx,[si]
cmp cx,[input+3]
jne rdfindnextdir
mov cx,[si+2]
cmp cx,[input+3+2]
jne rdfindnextdir
mov cx,[si+4]
cmp cx,[input+3+4]
jne rdfindnextdir
mov cx,[si+6]
cmp cx,[input+3+6]
jne rdfindnextdir
mov cx,[si+8]
cmp cx,[input+3+8]
jne rdfindnextdir
;比较id
mov ah,[si-1]
cmp al,ah
jne rdfindnextdir
mov al,[si-3]
;查看文件夹是否还有文件
mov cl,218
mov bp,0-0x8000+4096-0x200+2
rdfinddirhavefile:
mov ah,[bp]
cmp al,ah
je rddirhavefile
add bp,14
dec cl
jnz rdfinddirhavefile
;删除文件夹
sub si,3
mov cl,14
mov al,0xe1
rddeldir:
mov [si],al
add si,1
dec cl
jnz rddeldir
mov ah,03h
int 10h
mov di,dx
mov bx,0-0x8000+0x200
mov ah,03h
mov al,6 ;写6个扇区
mov ch,0
mov cl,3 ;3扇区开始
mov dl,0
mov dh,0
int 13h
mov ah,02h
mov dx,di
int 10h
jmp Command
rdfindnextdir:
add si,14
dec bl
jnz rdfinddir
;说明没有这个文件
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,rdnofinddirmsg
mov cx,13
mov bl,0x07
mov bh,0
int 10h
mov bl,10
mov si,3
rdshowdir:
mov ah,0eh
mov al,[input+si]
int 10h
add si,1
dec bl
jnz rdshowdir
jmp Command
rddirhavefile:
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,rddirhavefilemsg
mov cx,50
mov bl,0x07
mov bh,0
int 10h
jmp Command
rddirhavefilemsg db "This folder still has files and cannot be deleted."
rdnofinddirmsg db "No find dir: "
;-------------------------------------------------------------write命令------------------------------------------------------
writecommand:
;命灵格式:write 内容>>文件名,例如:write Hello>>My1.txt,将Hello写到My1.txt末尾,且会自动添加回车,文件不存在会报错。还可以write >>My1.txt,直接填回车。
;找终止符
mov ah,03h
int 10h
mov di,dx
mov si,6
mov cl,114 ;最多120字节的命令,120-(6-1)=114
writefindexitcode:
mov bx,[input+si]
cmp bx,">>" ;匹配到终止符去找文件
je writefindfile
add si,1
dec cl
jnz writefindexitcode
mov dx,di
mov ah,13h
mov al,1
mov bp,writenoentryexitcodemsg
mov cx,49
mov bl,0x07
mov bh,0
int 10h
jmp Command
;找不到,说明没有输入>>,抛出错误
writenoentryexitcodemsg db "You did not enter the file content terminator: >>"
writefindfile:
mov ah,02h
mov dx,di
int 10h
;检测是否输入文件名超10字节
add si,2
mov al,[input+si+11]
cmp al,0x00
jne writefiletobig
;先将0x00换成0x20
mov cl,10
mov ch,0
writeset0to20:
mov al,[input+si]
cmp al,0x00
je writeset0to20run
cmp al,0x20
je writeset0to20run
add si,1
dec cl
jnz writeset0to20
jmp writefile
writeset0to20run:
mov al,0x20
mov [input+si],al
add ch,1
add si,1
dec cl
jnz writeset0to20
jmp writefile
writenoentryfilename:
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,writenoentryfilenamemsg
mov cx,30
mov bl,0x07
mov bh,0
int 10h
jmp Command
writefiletobig:
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,writefiletobigmsg
mov cx,32
mov bl,0x07
mov bh,0
int 10h
jmp Command
writenoentryfilenamemsg db "You did not enter a file name."
writefiletobigmsg db "No file is larger than 10 bytes."
writefile:
cmp ch,10
je writenoentryfilename
sub si,10
mov bp,0-0x8000+4096-512+3
mov cl,218
pop ax
push ax
writefindfilename:
mov cx,[bp]
cmp cx,[input+si]
jne writefindnextfile
mov cx,[bp+2]
cmp cx,[input+si+2]
jne writefindnextfile
mov cx,[bp+4]
cmp cx,[input+si+4]
jne writefindnextfile
mov cx,[bp+6]
cmp cx,[input+si+6]
jne writefindnextfile
mov cx,[bp+8]
cmp cx,[input+si+8]
jne writefindnextfile
mov ah,[bp-1]
cmp al,ah
jne writefindnextfile
mov ax,[bp-3]
mov cl,al
mov al,ah
mov ah,cl
and ah,0fh
cmp ax,1
je writefindend
;ds指向文件段
mov bx,09a0h
writesetds:
add bx,0x20
dec ax
jnz writesetds
writefindend:
;开始寻找结尾mov ax,0,int 88h
mov ds,bx
mov di,0
writefindendrun:
mov al,[di]
cmp al,0xb8
je writeiffindend
writefindadddi:
add di,1
cmp di,16
je writeaddds
jmp writefindendrun
writeaddds:
mov di,0
mov bx,ds
add bx,1
mov ds,bx
jmp writefindendrun
writefindnextfile:
add bp,14
dec cl
jnz writefindfilename
mov ah,03h
int 10h
mov ah,13h
mov al,1
mov bp,writenofindfilemsg
mov cx,14
mov bl,0x07
mov bh,0
int 10h
mov cl,10
writeshowfile:
mov ah,0eh
mov al,[input+di]
int 10h
add di,1
dec cl
jnz writeshowfile
jmp Command
writenofindfilemsg db "No find file: "
writeiffindend:
mov cx,[di+1]
cmp cx,0x0000
jne writefindadddi
mov cx,[di+3]
cmp cx,0x88cd
jne writefindadddi
;开始写入内存
mov bp,6
writewritefile:
mov ax,[input+bp]
cmp ax,">>"
je writewritefin
mov al,[input+bp]
mov [di],al
add bp,1
add di,1
jmp writewritefile
writewritefin:
;写回车
mov ax,0x0d0a
mov [di],ax
;写入结束符
mov al,0xb8
mov [di+2],al
mov ax,0x000
mov [di+3],ax
mov ax,0x88cd
mov [di+5],ax
;写入扇区
mov bx,0x7c00+7168+512 ;文件起始段
mov ah,03h
mov al,51 ;写完剩下的扇区
mov ch,0
mov cl,15 ;15扇区开始
mov dl,0
mov dh,0
int 13h
mov bx,0
mov ds,bx
jmp Command
;----------------------------------------------------------------------------------------------------------------------------
db 0xb8,0x00,0x00,0xcd,0x88 ;文件储存结束符
times 0xf4ffe-7*1024-($-$$) db 0xe2
db 0x55,0xaa
Kernel.sys可是最主要的代码了,写完它之后,我感觉16位实模式汇编其实完全没有什么知识点,只要懂内存操作和中断即可。
这也是分为两部分,1、Kernel.sys代码 2、构建剩余文件储存扇区
Step2:知识点
源码有了,总不能就结束了吧,其中新增知识点得讲一下吧。
1、ah=2 int 13h读硬盘
这个中断很简单,bx就是读硬盘扇区要放到的内存地址。
2、ah=3 int 13h写硬盘
跟读硬盘一样,只不过就是bx放需要写入硬盘的地址。
3、cmp指令
cmp可以比较内存、寄存器,很简单。
4、内存操作
内存是ds:[偏移值]
ds位基础段,偏移值可以使用指针寄存器代替
mov [地址],寄存器
就可以将某个寄存器的值放到地址里去,要注意的是,写入内存后会写反
例如:
mov ax,1234h
mov [0x7c00],ax
那现在7c00的值是多少呢?( )
A:1234H B:4321H C:3412H D:2134H
正确答案:C
并且读内存也是一样
例如:
7c00H是1234h
mov ax,[7c00H]
那么现在ax就是,不用说了吧,是3412H
其实,汇编知识点并不多,汇编虽然是在计算机硬件底层的,但是开发效率非常慢,比如mov ah,0eh在文本占了10字节,而编译出来只有2字节。还有要看你是否有心好的心态,有耐心去调试、运行。虽然这个过程很痛苦(我也试过砸键盘、砸鼠标),但是每次都会静下心来,继续开发,成功之后的成功感能让自己感觉所有的辛苦、努力都值了。
Step3:编译和运行
由于代码量过多,编译有可能因为nasm版本过旧导致报错,这里我附上我的开发环境和nasm版本。
开发环境:Microsoft Windows 11 22H2 企业版
nasm版本:2.15.05 compiled on Aug 28 2020
编译bat脚本:
nasm Boot.asm -o Boot.bin
nasm Kernel.asm -o Kernel.sys
copy /b Boot.bin + Kernel.sys Task.img
这样,我们就得出了最后的成果:Task.img!
Step4 虚拟机运行:
我这里使用的是Vmware 17,虚拟机版本也是Vmware 17,运行也没有问题,应该不会存在版本兼容性问题。
用的是A:软驱。
由于CSDN不能加载视屏,所以自己尝试吧!
命令有:
cd :直接写cd,cd ..,cd 或cd /,cd 文件名,cd .>创建的文件名
cls:清屏
dir:列出该目录下的文件夹和文件
mkdir:在该目录新建文件夹
type:读取文件内容
del:删除文件
rd:删除文件夹(必须空目录)
write:write 文件内容>>文件名
基本包含了所有dos文件操作,还不能运行程序。write命令有一个bug,就是如果去到其他文件的储存区不会跳过,会直接写入,损坏其他文件,会在以后修复。
Step4:崩溃指令
在启动后输入以下指令:
cd TASK
del Kernel.sys
这指令也不用多说,作死删除内核
你会发现虚拟机完全卡住了
重启之后:
意料之中????
但是,当我们打开Task.bin后,发现Kernel.sys的内容并没有被抹除,而是只被抹除了文件名。
原因其实很简单,抹除内存时,将运行中的抹除程序给抹除掉了,所以导致死机。
这篇文章到这就结束了!
希望大家能留几个点赞加关注。
谢谢大家了,真的很不容易。
我们在开发操作系统(7)中再见
最后
以上就是坚定早晨为你收集整理的开发操作系统(7) DOS(2)DOS源码的全部内容,希望文章能够帮你解决开发操作系统(7) DOS(2)DOS源码所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复