首页 资讯 > > 正文

自己动手从零写桌面操作系统GrapeOS系列教程——23.从硬盘读取文件 天天亮点

来源:博客园 发布日期:2023-03-24 22:18:09 分享到:

学习操作系统原理最好的方法是自己写一个简单的操作系统。

本讲代码文件为boot.asm,要读取的文件为data.txt。


(资料图片)

一、在FAT16文件系统中读取文件的流程

在GrapeOS中用到的文件少且小,所有文件都放在了根目录下,数量不会超过16个,占用的簇不会超过254个。所以读取目录项只需要读取根目录的第1个扇区即可,读取FAT表项也只需读取FAT1表的第1个扇区即可。以下是读取文件的流程图:

二、代码及讲解

boot.asm中的代码如下:

;--------------------定义常量--------------------;FAT16目录项中各成员的偏移量:;名称    偏移    长度描述DIR_Name    equ 0;11文件名8B,扩展名3BDIR_Attr    equ 11;1目录项属性;保留位            12   10保留位DIR_WrtTime     equ 22;2最后一次写入时间DIR_WrtDate     equ 24;2最后一次写入日期DIR_FstClus     equ 26;2起始簇号DIR_FileSize    equ 28;4文件大小BOOT_ADDRESS equ 0x7c00 ;boot程序加载到内存的地址。FILE_ADDRESS equ 0x1000 ;文件读到内存中的地址。DISK_BUFFER  equ 0x7e00 ;读磁盘临时存放数据用的缓存区,放到boot程序之后。DISK_SIZE_M equ 4 ;磁盘容量,单位M。FAT1_SECTORS     equ 32 ;FAT1占用扇区数ROOT_DIR_SECTORS equ 32 ;根目录占用扇区数SECTOR_NUM_OF_FAT1_START     equ 1 ;FAT1表起始扇区号SECTOR_NUM_OF_ROOT_DIR_START equ 33 ;根目录区起始扇区号SECTOR_NUM_OF_DATA_START     equ 65 ;数据区起始扇区号,对应簇号为2。SECTOR_CLUSTER_BALANCE       equ 63 ;簇号加上该值正好对应扇区号。FILE_NAME_LENGTH     equ 11 ;文件名8字节加扩展名3字节共11字节。DIR_ENTRY_SIZE       equ 32 ;目录项为32字节。DIR_ENTRY_PER_SECTOR equ 16 ;每个扇区能存放目录项的数目。;--------------------MBR开始--------------------org BOOT_ADDRESSjmp boot_startnop;FAT16参数区:BS_OEMName db "GrapeOS "   ;厂商名称(8字节,含空格)BPB_BytesPerSec dw 0x0200;每扇区字节数BPB_SecPerClusdb 0x01;每簇扇区数BPB_RsvdSecCntdw 0x0001;保留扇区数(引导扇区的扇区数)BPB_NumFATsdb 0x01;FAT表的份数BPB_RootEntCntdw 0x0200;根目录可容纳的目录项数BPB_TotSec16dw 0x2000 ;扇区总数(4MB)BPB_Mediadb 0xf8 ;介质描述符BPB_FATSz16dw 0x0020;每个FAT表扇区数BPB_SecPerTrkdw 0x0020;每磁道扇区数BPB_NumHeadsdw 0x0040;磁头数BPB_hiddSecdd 0x00000000;隐藏扇区数BPB_TotSec32dd 0x00000000;如果BPB_TotSec16是0,由这个值记录扇区数。BS_DrvNumdb 0x80;int 13h的驱动器号BS_Reserved1db 0x00;未使用BS_BootSigdb 0x29;扩展引导标记BS_VolIDdd 0x00000000   ;卷序列号BS_VolLabdb "Grape OS   ";卷标(11字节,含空格)BS_FileSysTypedb "FAT16   ";文件系统类型(8字节,含空格);通过以上参数可知硬盘容量为4MB,共8K个扇区。扇区具体分布如下:;区域名     扇区数      扇区号          字节偏移            说明;引导扇区   1个扇区     扇区0           0x0000~0x01ff;FAT1表     32个扇区    扇区1~32        0x0200~0x41ff   可记录8K-2个簇;FAT2表     无          无              无              无;根目录区   32个扇区    扇区33~64       0x4200~0x81ff   可容纳512个目录项;数据区     8127个扇区  扇区65~0x1fff   0x8200~0x3fffff;--------------------程序开始--------------------boot_start:;初始化寄存器mov ax,csmov ds,axmov es,ax ;cmpsb会用到ds:si和es:di;读取文件开始;读取根目录的第1个扇区(1个扇区可以存放16个目录项,我们用到的文件少,不会超过16个。)mov esi,SECTOR_NUM_OF_ROOT_DIR_START mov di,DISK_BUFFERcall func_read_one_sector;在16个目录项中通过文件名查找文件cld ;cld将标志位DF置0,在串处理指令中控制每次操作后让si和di自动递增。std相反。下面repe cmpsb会用到。mov bx,0 ;用bx记录遍历第几个目录项。next_dir_entry:mov si,bxshl si,5 ;乘以32(目录项的大小)add si,DISK_BUFFER              ;源地址指向目录项中的文件名。mov di,read_file_name_string  ;目标地址指向文件在硬盘中的正确文件名。mov cx,FILE_NAME_LENGTH ;字符比较次数为FAT16文件名长度,每比较一个字符,cx会自动减一。repe cmpsb ;逐字节比较ds:si和es:di指向的两个字符串。jcxz file_found ;当cx为0时跳转,cx为0表示上面比较的两个字符串相同。找到了文件。inc bxcmp bx,DIR_ENTRY_PER_SECTORjl next_dir_entry ;检查下一个目录项。jmp file_not_found ;没有找到文件。file_found: ;找到了文件;从目录项中获取文件的起始簇号shl bx,5 ;乘以32add bx,DISK_BUFFERmov bx,[bx+DIR_FstClus] ;文件的起始簇号;读取FAT1表的第1个扇区(我们用到的文件少且小,只用到了该扇区中的簇号。)mov esi,SECTOR_NUM_OF_FAT1_START mov di,DISK_BUFFER ;放到boot程序之后call func_read_one_sectormov bp,FILE_ADDRESS ;文件内容读取到内存中的起始地址;按簇号读文件内容read_file: xor esi,esi ;esi清零mov si,bx ;簇号add esi,SECTOR_CLUSTER_BALANCEmov di,bpcall func_read_one_sectoradd bp,512 ;下一个目标地址;获取下一个簇号(每个FAT表项为2字节)shl bx,1 ;乘2,每个FAT表项占2个字节mov bx,[bx+DISK_BUFFER];判断下一个簇号cmp bx,0xfff8 ;大于等于0xfff8表示文件的最后一个簇jb read_file ;jb无符号小于则跳转,jl有符号小于则跳转。read_file_finish: ;读取文件结束jmp stopfile_not_found: ;没有找到文件stop:hltjmp stop;读取硬盘1个扇区(主硬盘控制器主盘);输入参数:esi,ds:di。;esi LBA扇区号;ds:di 将数据写入到的内存起始地址;输出参数:无。func_read_one_sector:;第1步:检查硬盘控制器状态mov dx,0x1f7.not_ready1:nop ;nop相当于稍息 hlt相当于睡觉in al,dx ;读0x1f7端口and al,0xc0 ;第7位为1表示硬盘忙,第6位为1表示硬盘控制器已准备好,正在等待指令。cmp al,0x40 ;当第7位为0,且第6位为1,则进入下一个步。jne .not_ready1 ;若未准备好,则继续判断。;第2步:设置要读取的扇区数mov dx,0x1f2mov al,1out dx,al ;读取1个扇区;第3步:将LBA地址存入0x1f3~0x1f6mov eax,esi;LBA地址7~0位写入端口0x1f3mov dx,0x1f3out dx,al;LBA地址15~8位写入端口写入0x1f4shr eax,8mov dx,0x1f4out dx,al;LBA地址23~16位写入端口0x1f5shr eax,8mov dx,0x1f5out dx,al;第4步:设置device端口shr eax,8and al,0x0f ;LBA第24~27位or al,0xe0 ;设置7~4位为1110,表示LBA模式,主盘mov dx,0x1f6out dx,al;第5步:向0x1f7端口写入读命令0x20mov dx,0x1f7mov al,0x20out dx,al;第6步:检测硬盘状态.not_ready2:nop ;nop相当于稍息 hlt相当于睡觉in al,dx ;读0x1f7端口and al,0x88 ;第7位为1表示硬盘忙,第3位为1表示硬盘控制器已准备好数据传输。cmp al,0x08 ;当第7位为0,且第3位为1,进入下一步。jne .not_ready2 ;若未准备好,则继续判断。;第7步:从0x1f0端口读数据mov cx,256 ;每次读取2字节,一个扇区需要读256次。mov dx,0x1f0.go_on_read:in ax,dxmov [di],axadd di,2loop .go_on_readretread_file_name_string:db "DATA    TXT",0  ;要读取的文件在硬盘中存储的文件名,共11个字节,含空格。times 510-($-$$) db 0db 0x55,0xaa

关于代码的讲解基本都写在注释中了,结合之前讲的内容,大家应该能看懂。

三、通过Linux将文件复制到虚拟硬盘中

本讲要读取的文件是data.txt,如何将该文件复制到虚拟硬盘的FAT16文件系统中呢?我们这里采用的方法是将该虚拟硬盘挂载到Linux系统上,然后就可以将data.txt复制到虚拟硬盘中了。前提是需要先将虚拟硬盘格式化,格式化的方法就是将boot程序写入到虚拟硬盘的第一个扇区。因为boot程序中含有FAT16的结构化数据,Linux系统就知道如何读写该文件系统了。

1.将boot程序写入到虚拟硬盘的第一个扇区
dd if=/dev/zero of=/media/VMShare/GrapeOS.img bs=1M count=4nasm boot.asm -o boot.bindd if=boot.bin of=/media/VMShare/GrapeOS.img conv=notrunc

截图如下:

2.将虚拟硬盘挂载到Linux系统上并将data.txt复制到虚拟硬盘中
mount /media/VMShare/GrapeOS.img /mnt/ -t msdos -o loopll /mnt/cp data.txt /mnt/sync #数据同步,立马把数据写入硬盘。ll /mnt/umount /mnt/

截图如下:

上图中在复制完data.txt后,通过ll /mnt/查看虚拟硬盘根目录,此时虽然看到的文件名是小写“data.txt”,但实际上在虚拟硬盘里存储的文件名已经是全部大写的了,在下面的分析中可以看到。

3.虚拟硬盘数据分析

通过hexdump查看虚拟硬盘数据:

hexdump /media/VMShare/GrapeOS.img -C

截图如下:

截图中的部分数据如下:

000001f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 55 aa  |..............U.|00000200  00 00 00 00 00 00 04 00  05 00 ff ff 00 00 00 00  |................|00000210  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|*00004200  44 41 54 41 20 20 20 20  54 58 54 20 00 00 00 00  |DATA    TXT ....|00004210  00 00 00 00 00 00 fa 4e  78 56 03 00 58 04 00 00  |.......NxV..X...|00004220  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

前面我们计算过,FAT1表的起始扇区是扇区1,字节偏移是0x200,根目录区的起始扇区是扇区33,字节偏移是0x4200。从上面的截图和数据可以看到:

在根目录区的第一个目录项就是我们要读的文件,文件名已是全大写。从目录项中可以看到文件的起始簇号是0x0003。在FAT表中第3个FAT表项的值是0x0004,表示该文件的第二个簇号是0x0004。在FAT表中第4个FAT表项的值是0x0005,表示该文件的第三个簇号是0x0005。在FAT表中第5个FAT表项的值是0xffff,表示该文件没有下一个簇了,到此结束。这个文件的内容共占用3个簇的空间,依次是簇3、簇4、簇5,读取该文件就是依次将这3个簇中的数据读取出来。四、程序演示

在cmd命令行中启动QEMU的调试模式:

C:\Users\CYJ>qemu-system-i386 d:\GrapeOS\VMShare\GrapeOS.img -S -s

在Linux命令行中启动GDB:

[root@CentOS7 Lesson23]# gdb(gdb) target remote 你的Windows的IP地址:1234(gdb) b *0x7c00(gdb) c(gdb) x /32xb 0x1000 #在读文件前查看此时0x1000处的内存数据,可以看到都是0。0x1000: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x000x1008: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x000x1010: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x000x1018: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00(gdb) c运行几秒,然后Ctrl键+C键暂停运行,此时读取文件的程序已运行完毕。(gdb) x /32xb 0x1000 #在读完文件后查看此时0x1000处的内存数据,可以看到已经不是0了。0x1000: 0x78    0x38    0x36    0x20    0x28    0x61    0x6c    0x730x1008: 0x6f    0x20    0x6b    0x6e    0x6f    0x77    0x6e    0x200x1010: 0x61    0x73    0x20    0x38    0x30    0x78    0x38    0x360x1018: 0x20    0x6f    0x72    0x20    0x74    0x68    0x65    0x20(gdb) x /32c 0x1000 #为了方便观察可以以字符形式展示数据。通过对比,下面的32个字符的确和data.txt中前32个字符相同。0x1000: 120 "x" 56 "8"  54 "6"  32 " "  40 "("  97 "a"  108 "l" 115 "s"0x1008: 111 "o" 32 " "  107 "k" 110 "n" 111 "o" 119 "w" 110 "n" 32 " "0x1010: 97 "a"  115 "s" 32 " "  56 "8"  48 "0"  120 "x" 56 "8"  54 "6"0x1018: 32 " "  111 "o" 114 "r" 32 " "  116 "t" 104 "h" 101 "e" 32 " "(gdb) x /32c 0x1440 #查看文件的最后二十多个字符。通过对比可以看到和data.txt中的相同。0x1440: 105 "i" 116 "t" 115 "s" 32 " "  90 "Z"  105 "i" 108 "l" 111 "o"0x1448: 103 "g" 32 " "  90 "Z"  45 "-"  56 "8"  48 "0"  32 " "  118 "v"0x1450: 97 "a"  114 "r" 105 "i" 97 "a"  110 "n" 116 "t" 41 ")"  46 "."0x1458: 0 "\000" 0 "\000" 0 "\000" 0 "\000" 0 "\000" 0 "\000" 0 "\000" 0 "\000"

通过上述演示说明读取文件成功。

视频版地址:https://www.bilibili.com/video/BV1xN411K7Lc/配套的代码与资料在:https://gitee.com/jackchengyujia/grapeos-courseGrapeOS操作系统交流QQ群:643474045

关键词:

x 广告

河北印发出台通用机场布局规划(2021-2030年)

到2030年,全省形成以A类通用机场为主体、B类通用机场为补充,功能完善、覆盖广泛的通用机场体系,全省通用机场达到23个。其中,到2025年全

复原民国旧菜单 一批“消失的名菜”重现羊城

  中新网广州12月5日电 (记者 程景伟)“粤宴中国·消失的名菜”活动4日晚在广州博物馆镇海楼广场举行,一批业已失传或十分罕见的传统粤

青海再度“双清零”:战“疫”催生定点救治医院反思与成长

  中新网西宁12月5日电 题:青海再度“双清零”:战“疫”催生定点救治医院反思与成长  作者 潘雨洁  全面停诊、四下无人;火线冲

世界海拔最高高铁客运站山丹马场站运营

  中新网兰州12月5日电 (记者 杨艳敏)记者从中国铁路兰州局集团有限公司获悉,12月5日10时29分随着嘉峪关南至西安北D2696次动车组列车

千年古都洛阳为何要建青年友好型城市?

  中新网洛阳12月5日电 题:千年古都洛阳为何要建青年友好型城市?  记者 肖开霖 李贵刚  千年古都洛阳日前公布《洛阳市建设青年

甘肃万余河长公示牌拥有“电子身份证” 局地启“千里眼”治水

  中新网兰州12月5日电 (记者 冯志军)记者5日从甘肃省水利厅获悉,今年以来,甘肃全面推动河长公示牌信息化建设,为全省河流换发“电子

满洲里市向呼伦贝尔市“手递手”异地转运3批次隔离人员

  (抗击新冠肺炎)满洲里市向呼伦贝尔市“手递手”异地转运3批次隔离人员  中新网呼伦贝尔12月5日电 (记者 张玮)5日,内蒙古自治区呼

2021年度法治人物沈云如:让群众过上“有身份的生活”

  中新网杭州12月5日电 题:2021年度法治人物沈云如:让群众过上“有身份的生活”  作者 郭其钰 张先登  行程10余万公里,为辖区3

x 广告

Copyright   2015-2023 今日海洋网版权所有  备案号:沪ICP备2023005074号-40   联系邮箱:5 85 59 73 @qq.com