codefans

          導(dǎo)航

          <2025年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          統(tǒng)計(jì)

          常用鏈接

          留言簿(2)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          程序設(shè)計(jì)鏈接

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          [開發(fā)教程]FAT 12 文件系統(tǒng)簡(jiǎn)介

          小謝 發(fā)表于 2005-8-26 11:51:06

            有不少朋友在論壇或是發(fā)郵件給我,問關(guān)于FAT12的問題。對(duì)一些開發(fā)操作系統(tǒng)的朋友來說,軟盤或軟盤鏡像是不可或缺的系統(tǒng)載體,我們的操作系統(tǒng)要在存儲(chǔ)介質(zhì)上操作就幾乎不可能離開文件系統(tǒng),如果想了解一下FAT12、FAT16、FAT32之類的Windows 用過的文件系統(tǒng),可以去:http://www.yesky.com/20030313/1656880.shtml 
          如果想全面地了解硬盤結(jié)構(gòu),文件系統(tǒng)原理,下面的一系列文章是很不錯(cuò)的材料:
          http://www.sjhf.net/Article/sjhfdoc/200404/1.html
          http://www.sjhf.net/Article/sjhfdoc/200404/2.html
          http://www.sjhf.net/Article/sjhfdoc/200404/3.html
          http://www.sjhf.net/Article/sjhfdoc/200404/4.html
          http://www.sjhf.net/Article/Index.html

            本文主要介紹以3.5英寸的1.44M標(biāo)準(zhǔn)格式化的FAT12文件系統(tǒng)的軟盤為介紹對(duì)象。這里強(qiáng)調(diào)那么多是因?yàn)椋?.44M的軟盤格式化可以不是1.44M,可以大于也可以小于;格式化的文件系統(tǒng)也可以不是FAT12。

            為什么會(huì)出現(xiàn)正常的1.44M軟盤格式化后可大可小的情況呢?從軟盤及軟盤驅(qū)動(dòng)器原理出發(fā),軟盤的尋址方式(可以認(rèn)為是讀取數(shù)據(jù)的方式)是:CHS,C = Cylinder(柱面),H = Header(磁頭),S = Sector(扇區(qū))。標(biāo)準(zhǔn)地格式化后,磁盤將被格式化為 每面80磁道(80個(gè)同心圓,柱面),每個(gè)磁道有18個(gè)扇區(qū),每個(gè)扇區(qū)是 512字節(jié),那么高密3.5英寸軟盤的容量為:2×80×18×512 = 1474560 Byte = 1440 KB = 1.44 MB。然而,軟盤可以不格式為80磁道,每個(gè)磁道也可以不是18扇區(qū),這是題外話,如果您有興趣,可以用古老的HDCopy試試。

            文件存儲(chǔ)到磁盤上時(shí)至少要占用1個(gè)扇區(qū),即使這個(gè)文件只有1個(gè)字節(jié),如果文件有513字節(jié),那就得占用2個(gè)扇區(qū),下一個(gè)文件就不能用這只使用了一個(gè)字節(jié)的扇區(qū)。即軟盤以扇區(qū)為單位存儲(chǔ)文件。現(xiàn)在用下面的假設(shè)來說明本文的目的:
            假設(shè)只有18個(gè)扇區(qū)的磁盤,以 0 - 17 編址,如果一個(gè)文件保存在 1 - 6扇區(qū),另一文件保存在 7 - 16扇區(qū),如果我們對(duì)第一個(gè)文件增加了內(nèi)容,又需要一個(gè)扇區(qū)來保存它,但由于文件連續(xù)存儲(chǔ), 7號(hào)扇區(qū)是第二個(gè)文件的,我們當(dāng)然不能用它,只有最后留有一個(gè)扇區(qū)可用,我們會(huì)不會(huì)把第二個(gè)文件先挪到8-17扇區(qū)以騰出一個(gè)扇區(qū)來給第一個(gè)文件使用呢?當(dāng)只有少數(shù)兩個(gè)文件的時(shí)候可以,但有很多文件的時(shí)候會(huì)變得麻煩起來。如果我們用一個(gè)表來表示有一個(gè)文件占用了 1-6扇區(qū) 和 17扇區(qū),那事情就簡(jiǎn)單了——我們不必為文件不連續(xù)而煩惱。這個(gè)表就叫它:文件分配表(File Allocation Table)。那怎樣才能知道這個(gè)文件存儲(chǔ)的文件名和文件存放的起始扇區(qū)?再建一個(gè)表,用于存放文件名、起始扇區(qū)、文件創(chuàng)建時(shí)間、文件實(shí)際大小等等資料,這個(gè)表叫:文件目錄表(File Directory Table)。將這兩個(gè)表放在磁盤指定的位置,以便操作系統(tǒng)使用,磁盤的其它扇區(qū)全都用來存放文件的實(shí)際內(nèi)容,這就構(gòu)成了有文件系統(tǒng)的磁盤。

            磁盤上,0面0磁道第1扇區(qū)用于存放引導(dǎo)程序,如果這512字節(jié)最后兩個(gè)字節(jié)分別是0x55,0xAA(一個(gè)字是0xAA55),稱為可引導(dǎo)標(biāo)志,BIOS會(huì)將這512字節(jié)讀取出來執(zhí)行,操作系統(tǒng)便是利用這里來實(shí)現(xiàn)引導(dǎo)的。標(biāo)識(shí)軟盤是不是FAT12并不是沒有根據(jù)的,在這512字節(jié)中,還有一個(gè)設(shè)備頭用于標(biāo)識(shí)這個(gè)軟盤(設(shè)備),例子如下:

          ;===========================================================================
          ; 程序執(zhí)行的第一條指令必須是跳轉(zhuǎn)(如果你想使用FAT12這類文件系統(tǒng)的磁盤)

          ; 必須占用3字節(jié)
          ;===========================================================================
          jmp SHORT main ; 2 bits,跳轉(zhuǎn)到主程序執(zhí)行
          nop            ; 1 bit
          ;===========================================================================
          ; FAT12 文件系統(tǒng)頭,從NYAOS 借過來的,可以參考相關(guān)的文檔以獲得更多細(xì)節(jié)
          ; 這個(gè)塊會(huì)讓 Winimage 認(rèn)出編譯后的二進(jìn)制文件為有效的引導(dǎo)文件
          ; 如果不使用這個(gè)塊,Winimage將不會(huì)將其作為引導(dǎo)程序處理
          ; 但我們可以借助其它方法和工具處理,比如DEBUG
          ;===========================================================================
          bsOEM       db "ExOS0.02"               ; OEM String,任意你喜歡的8字節(jié)ASCII碼
          bsSectSize  dw 512                      ; Bytes per sector
          bsClustSize db 1                        ; Sectors per cluster
          bsRessect   dw 1                        ; # of reserved sectors
          bsFatCnt    db 2                        ; # of fat copies
          bsRootSize  dw 224                      ; size of root directory
          bsTotalSect dw 2880                     ; total # of sectors if < 32 meg
          bsMedia     db 0xF0                     ; Media Descriptor
          bsFatSize   dw 9                        ; Size of each FAT
          bsTrackSect dw 18                       ; Sectors per track
          bsHeadCnt   dw 2                        ; number of read-write heads
          bsHidenSect dd 0                        ; number of hidden sectors
          bsHugeSect  dd 0                        ; if bsTotalSect is 0 this value is
                                                  ; the number of sectors
          bsBootDrv   db 0                        ; holds drive that the bs came from
          bsReserv    db 0                        ; not used for anything
          bsBootSign  db 29h                      ; boot signature 29h
          bsVolID     dd 0                        ; Disk volume ID also used for temp
                                                  ; sector # / # sectors to load
          bsVoLabel   db "NO NAME    "            ; Volume Label
          bsFSType    db "FAT12   "               ; File System type <- FAT 12文件系統(tǒng)
          ;===========================================================================
          ; Main start here
          ;===========================================================================
          main:
          #至于如何引導(dǎo)計(jì)算機(jī),可以參考我Blog里的more.asp?name=xemean&id=2

            0面0道第2扇區(qū)到第10扇區(qū)的9個(gè)扇區(qū)是FAT表的存放位置,為了預(yù)防,0面0道的第11扇區(qū)到1面0道第1扇區(qū)的9個(gè)扇區(qū)是第2個(gè)FAT表的存放位置,這第2個(gè)FAT是備用的,當(dāng)?shù)谝粋€(gè)FAT出了問題里,可以用第2個(gè)FAT。1面0道的第2扇區(qū)起到1面0道的第15扇區(qū)(共14個(gè)扇區(qū))用于存放 FDT。FDT沒有備份,所以沒有第二個(gè)FDT。這里要注意的是,磁盤為了讀寫的速度,0面0道的18個(gè)扇區(qū)接下來的是 1面0道的扇區(qū),而不是0面1道,因?yàn)?面0道跟1面0道同在一個(gè)柱面上(同心圓),只是用的磁頭不同。

            FAT12 中,每個(gè)文件分配表項(xiàng)只占12位(bit),即1.5字節(jié)(byte),每個(gè)表項(xiàng)代表一個(gè)扇區(qū),在這里,磁盤只有扇區(qū)的概念,磁盤里所有扇區(qū)都被類似于上一段提到的磁盤讀寫方式線性地編址(LBA),不再有CHS。這里還要提一提簇的概念:DOS會(huì)把2個(gè)扇區(qū)作為一簇,那么文件就要以簇為單位讀寫。簇的大小通常根據(jù)磁盤的大小設(shè)定,以盡可能少浪費(fèi)磁盤空間為本。

            FAT12每個(gè)表項(xiàng)的值指出文件存放的下一個(gè)扇區(qū)號(hào),同時(shí)也是表項(xiàng)入口。比如如果文件的存放的第一個(gè)扇區(qū)是002,那系統(tǒng)首先找FAT的002,在002處得到一個(gè)值003,表示文件下一個(gè)扇區(qū)是003號(hào),再接著003表項(xiàng)找,得到006...,表項(xiàng)的值含義如下:
          000 - 此簇未用;FF8 - FFF 該簇為文件的最后一簇;FF0 - FF7,此簇為壞,不可用;其它值表示文件下一簇的簇號(hào)。
            下面的圖來說明FAT的基本原理:
          表項(xiàng)編號(hào)  值(16位)   備注 
          000   | FF0  | <- 000 項(xiàng) 001項(xiàng)為表頭,1字節(jié) 0xF0表示存儲(chǔ)介質(zhì)
          001   | FFF  | <- 2、3字節(jié)為 0xFFFF ,固定值,F(xiàn)AT標(biāo)志
          002   | 003  | <- 文件下一簇為003
          003   | 005  | <- 下一簇:005
          004   | FF7  | <- 壞簇,不可用
          005   | 011  | <- 下一簇:011
          ........................................
          011   | FF8  | <- 該文件結(jié)束
          012   | 000  | <- 可用簇
          .......................................
          根據(jù)上表,我們可以知道,一個(gè)文件占用了 002,003,005,011 這4個(gè)簇。
            簇號(hào) + 31 = 邏輯扇區(qū)號(hào) //// 31 = 保留扇區(qū)數(shù) + 隱藏扇區(qū)數(shù) + FAT數(shù)×每個(gè)FAT所占扇區(qū)數(shù) + FDT所占扇區(qū)數(shù) - 2 = 1 + 0 + 2*18 + 14 -2
            LBA = 邏輯扇區(qū)號(hào) - 1
            扇區(qū) = (LBA MOD 每道扇區(qū)數(shù)) + 1
            磁道 = (LBA / 每道扇區(qū)數(shù)) / 磁頭數(shù)
            磁頭 = (LBA / 每道扇區(qū)數(shù)) MOD 磁頭數(shù)

          根據(jù)上面的公式,得到以下計(jì)算值:
          002: S = ( 32 MOD 18 ) + 1 = 15
          002: C = ( 32 / 18 ) / 2 = 0
          002: H = ( 32 / 18 ) MOD 2 = 1
          -----------------
          011: S = ( ( 11+31-1) MOD 18) + 1 = 6
          011: C = ( ( 11+31-1) / 18) / 2 = 1
          011: H = ( ( 11+31-1) / 18) MOD 2 = 0

            就此,我們已經(jīng)可心根據(jù)簇號(hào)得到物理CHS了,那怎樣才能得到一個(gè)文件的關(guān)系首簇號(hào)呢?前面我們提到了FDT。下面說說FDT的結(jié)構(gòu):
            每個(gè)FDT項(xiàng)占32字節(jié),分配如下:
          =======================
          0 - 7 : 8字節(jié),文件名
          8 - 10:  3字節(jié),文件擴(kuò)展名
          11 :1字節(jié),文件的屬性
          12 - 15:4字節(jié),保留
          16 - 21:6字節(jié),保留
          22 - 23:2字節(jié),文件最后修改時(shí)間(時(shí)分秒,5:6:5)
          24 - 25:2字節(jié),文件最后修改日期(年月日,7:4:5,年取0-119對(duì)應(yīng) 1980 - 2099)
          26 - 27:2字節(jié),文件首簇號(hào),我們可以根據(jù)這個(gè)值在FAT中找到文件的存儲(chǔ)位置
          28 - 31:4字節(jié),文件的長(zhǎng)度,以字節(jié)為單位
          ===========================
          0 - 7 文件名含義:0 - 目錄項(xiàng)為空,可用;E5 - 此文件已經(jīng)被刪除
          7 - 10 :文件名和擴(kuò)展名為8.3格式,如果不夠,必需用空格填充,即文件名如果只有6個(gè)字節(jié),那剩下的2個(gè)字節(jié)必須以空格填充。文件名和擴(kuò)展名都是大寫。
          11屬性字節(jié)含義:00 - 普通文件;01 - 只讀;02 - 隱藏;04 - 系統(tǒng)文件;10(1x) - 該文件是目錄。

            就此,本文已經(jīng)基本介紹完了軟盤的結(jié)構(gòu),下面介紹如何讀一個(gè)文件:

          1. 給出一個(gè)文件名,比如“KERNEL.SYS”
          2. 將文件名擴(kuò)展為“KERNEL  SYS”,即去掉點(diǎn)并為文件名和擴(kuò)展名補(bǔ)充空格
          3. 讀FDT到內(nèi)存中(用BIOS INT 13)
          4. 在FDT中查找到符合的文件名
          5. 可選,判斷在FDT中找到的是否是目錄
          6. 在符合的FDT中取出文件首簇號(hào)
          7. 讀入FAT,可以選擇讀入兩個(gè)FAT表,以檢查是否有效
          8. 將簇號(hào)轉(zhuǎn)換為CHS,將扇區(qū)讀入內(nèi)存
          9. 根據(jù)簇號(hào)在FAT中查找下一簇,并判斷是否是文件最后一簇
          10. 如果是文件最后一簇,則文件讀取完畢;如果不是,則轉(zhuǎn)第8步

            如果在引導(dǎo)程序中讀指定的內(nèi)核文件,則可以省略1、2步,直接給出內(nèi)核文件名即可。

            如果給出的文件是帶目錄的,那這里還有必要介紹一下:實(shí)際上,目錄也是一個(gè)文件,只不過這個(gè)文件是一個(gè)FDT,F(xiàn)DT指出該目錄下其它文件或目錄。因此,給出如下路徑:/EXOS/KERNEL.BIN ,則先是在根目錄中,將“EXOS    ”這個(gè)“文件”讀出來,然后在讀出的FDT中找“KERNEL  BIN”。

            好了,本文至此告一段落,但愿能給大家一定的幫助。近期正在寫一個(gè)ERP,時(shí)間倉促,本文寫得也有不盡如人意的地方,更沒有代碼實(shí)例。還請(qǐng)大家見諒。

          X.
          2005-08-26


          閱讀全文(73) | 回復(fù)(3) | 引用(0)
           


          回復(fù):FAT 12 文件系統(tǒng)簡(jiǎn)介
          future0906(游客)發(fā)表評(píng)論于2005-8-29 11:08:27
          以下引用xemean在2005-8-28 16:20:19的評(píng)論:

          表頭的三個(gè)字節(jié)的值是 0xFFFFF0,即第1個(gè)字節(jié)是0xF0,第二個(gè)字節(jié)是0xFF,第三個(gè)字節(jié)也是 0xFF。按照小拉丁寫法,高位在前(左),低位在后(右),所以寫成 FF0我認(rèn)為并沒有錯(cuò)。


          恩,我明白你的意思了~~,謝

          個(gè)人主頁 | 引用 | 返回
           


          回復(fù):FAT 12 文件系統(tǒng)簡(jiǎn)介
          xemean發(fā)表評(píng)論于2005-8-28 16:20:19

          表頭的三個(gè)字節(jié)的值是 0xFFFFF0,即第1個(gè)字節(jié)是0xF0,第二個(gè)字節(jié)是0xFF,第三個(gè)字節(jié)也是 0xFF。按照小拉丁寫法,高位在前(左),低位在后(右),所以寫成 FF0我認(rèn)為并沒有錯(cuò)。


          個(gè)人主頁 | 引用 | 返回
           

          posted on 2005-09-14 16:21 春雷的博客 閱讀(1149) 評(píng)論(0)  編輯  收藏


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 涿鹿县| 德钦县| 霍林郭勒市| 汕尾市| 临安市| 甘泉县| 象山县| 蕲春县| 攀枝花市| 磐石市| 怀化市| 宜都市| 冷水江市| 灌阳县| 全南县| 平顶山市| 郧西县| 潜山县| 鄂托克前旗| 诸暨市| 历史| 唐山市| 安康市| 荔波县| 张家界市| 邵武市| 泸水县| 海安县| 山阳县| 扎鲁特旗| 蕉岭县| 灵武市| 兴业县| 噶尔县| 阿拉尔市| 根河市| 永新县| 兴宁市| 花垣县| 兰考县| 光山县|