24,337 → 24,337 |
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
;***************************************************************************** |
|
Âñòðå÷àþòñÿ âèðóñ è FAT. |
- Ïðèâåò, òû êòî? |
- ß? Âèðóñ. |
- A ÿ AFT, òî åñòü TAF, òî åñòü FTA, ÷åðò, ñîâñåì çàïóòàëñÿ... |
Встречаются вирус и FAT. |
- Привет, ты кто? |
- Я? Вирус. |
- A я AFT, то есть TAF, то есть FTA, черт, совсем запутался... |
|
Áóòñåêòîð äëÿ FAT12/FAT16-òîìà íà íîñèòåëå ñ ðàçìåðîì ñåêòîðà 0x200 = 512 áàéò. |
Бутсектор для FAT12/FAT16-тома на носителе с размером сектора 0x200 = 512 байт. |
|
===================================================================== |
|
Åñòü äâå âåðñèè â çàâèñèìîñòè îò òîãî, ïîääåðæèâàåò ëè íîñèòåëü LBA, |
âûáîð îñóùåñòâëÿåòñÿ óñòàíîâêîé êîíñòàíòû use_lba â ïåðâîé ñòðîêå èñõîäíèêà. |
Òðåáîâàíèÿ äëÿ ðàáîòû: |
1) Ñàì áóòñåêòîð, ïåðâàÿ êîïèÿ FAT è âñå èñïîëüçóåìûå ôàéëû |
äîëæíû áûòü ÷èòàáåëüíû. |
2) Ìèíèìàëüíûé ïðîöåññîð - 80186. |
3) Â ñèñòåìå äîëæíî áûòü êàê ìèíèìóì 592K ñâîáîäíîé áàçîâîé ïàìÿòè. |
Есть две версии в зависимости от того, поддерживает ли носитель LBA, |
выбор осуществляется установкой константы use_lba в первой строке исходника. |
Требования для работы: |
1) Сам бутсектор, первая копия FAT и все используемые файлы |
должны быть читабельны. |
2) Минимальный процессор - 80186. |
3) В системе должно быть как минимум 592K свободной базовой памяти. |
|
===================================================================== |
|
Äîêóìåíòàöèÿ â òåìó (ññûëêè âàëèäíû íà ìîìåíò íàïèñàíèÿ ýòîãî ôàéëà, 15.05.2008): |
îôèöèàëüíàÿ ñïåöèôèêàöèÿ FAT: http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx |
â ôîðìàòå PDF: http://staff.washington.edu/dittrich/misc/fatgen103.pdf |
ðóññêèé ïåðåâîä: http://wasm.ru/docs/11/fatgen103-rus.zip |
îôèöèàëüíàÿ ñïåöèôèêàöèÿ ðàñøèðåíèÿ EDD BIOS 3.0: http://www.phoenix.com/NR/rdonlyres/19FEBD17-DB40-413C-A0B1-1F3F560E222F/0/specsedd30.pdf |
òî æå, âåðñèÿ 1.1: http://www.phoenix.com/NR/rdonlyres/9BEDED98-6B3F-4DAC-BBB7-FA89FA5C30F0/0/specsedd11.pdf |
îïèñàíèå ôóíêöèé BIOS: Interrupt List by Ralf Brown: http://www.cs.cmu.edu/~ralf/files.html |
îôèöèàëüíàÿ ñïåöèôèêàöèÿ Boot BIOS: http://www.phoenix.com/NR/rdonlyres/56E38DE2-3E6F-4743-835F-B4A53726ABED/0/specsbbs101.pdf |
Документация в тему (ссылки валидны на момент написания этого файла, 15.05.2008): |
официальная спецификация FAT: http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx |
в формате PDF: http://staff.washington.edu/dittrich/misc/fatgen103.pdf |
русский перевод: http://wasm.ru/docs/11/fatgen103-rus.zip |
официальная спецификация расширения EDD BIOS 3.0: http://www.phoenix.com/NR/rdonlyres/19FEBD17-DB40-413C-A0B1-1F3F560E222F/0/specsedd30.pdf |
то же, версия 1.1: http://www.phoenix.com/NR/rdonlyres/9BEDED98-6B3F-4DAC-BBB7-FA89FA5C30F0/0/specsedd11.pdf |
описание функций BIOS: Interrupt List by Ralf Brown: http://www.cs.cmu.edu/~ralf/files.html |
официальная спецификация Boot BIOS: http://www.phoenix.com/NR/rdonlyres/56E38DE2-3E6F-4743-835F-B4A53726ABED/0/specsbbs101.pdf |
|
===================================================================== |
|
Ìàêñèìàëüíîå êîëè÷åñòâî êëàñòåðîâ íà FAT12-òîìå - 0xFF4 = 4084; êàæäûé êëàñòåð |
çàíèìàåò 12 áèò â òàáëèöå FAT, òàê ÷òî îáùèé ðàçìåð íå ïðåâîñõîäèò |
0x17EE = 6126 áàéò. Âñÿ òàáëèöà ïîìåùàåòñÿ â ïàìÿòè. |
Ìàêñèìàëüíîå êîëè÷åñòâî êëàñòåðîâ íà FAT16-òîìå - 0xFFF4 = 65524; êàæäûé |
êëàñòåð çàíèìàåò 16 áèò â òàáëèöå FAT, òàê ÷òî îáùèé ðàçìåð íå ïðåâîñõîäèò |
0x1FFE8 = 131048 áàéò. Âñÿ òàáëèöà òàêæå ïîìåùàåòñÿ â ïàìÿòè, îäíàêî â |
ýòîì ñëó÷àå íåñêîëüêî íåöåëåñîîáðàçíî ñ÷èòûâàòü âñþ òàáëèöó, ïîñêîëüêó |
íà ïðàêòèêå íóæíà òîëüêî íåáîëüøàÿ å¸ ÷àñòü. Ïîýòîìó ìåñòî â ïàìÿòè |
ðåçåðâèðóåòñÿ, íî äàííûå ñ÷èòûâàþòñÿ òîëüêî â ìîìåíò, êîãäà ê íèì |
äåéñòâèòåëüíî èä¸ò îáðàùåíèå. |
Максимальное количество кластеров на FAT12-томе - 0xFF4 = 4084; каждый кластер |
занимает 12 бит в таблице FAT, так что общий размер не превосходит |
0x17EE = 6126 байт. Вся таблица помещается в памяти. |
Максимальное количество кластеров на FAT16-томе - 0xFFF4 = 65524; каждый |
кластер занимает 16 бит в таблице FAT, так что общий размер не превосходит |
0x1FFE8 = 131048 байт. Вся таблица также помещается в памяти, однако в |
этом случае несколько нецелесообразно считывать всю таблицу, поскольку |
на практике нужна только небольшая её часть. Поэтому место в памяти |
резервируется, но данные считываются только в момент, когда к ним |
действительно идёт обращение. |
|
Ñõåìà èñïîëüçóåìîé ïàìÿòè: |
...-7C00 ñòåê |
7C00-7E00 êîä áóòñåêòîðà |
7E00-8200 âñïîìîãàòåëüíûé ôàéë çàãðóç÷èêà (kordldr.f1x) |
8200-8300 ñïèñîê çàãðóæåííûõ ñåêòîðîâ òàáëèöû FAT16 |
(1 = ñîîòâåòñòâóþùèé ñåêòîð çàãðóæåí) |
60000-80000 çàãðóæåííàÿ òàáëèöà FAT12 / ìåñòî äëÿ òàáëèöû FAT16 |
80000-90000 òåêóùèé êëàñòåð òåêóùåé ðàññìàòðèâàåìîé ïàïêè |
90000-92000 êýø äëÿ êîðíåâîé ïàïêè |
92000-... êýø äëÿ íåêîðíåâûõ ïàïîê (êàæäîé ïàïêå îòâîäèòñÿ |
2000h áàéò = 100h âõîäîâ, îäíîâðåìåííî â êýøå |
ìîæåò íàõîäèòüñÿ íå áîëåå 7 ïàïîê; |
òî÷íûé ðàçìåð îïðåäåëÿåòñÿ ðàçìåðîì äîñòóïíîé |
ôèçè÷åñêîé ïàìÿòè - êàê ïðàâèëî, íåïîñðåäñòâåííî |
ïåðåä A0000 ðàçìåùàåòñÿ EBDA, Extended BIOS Data Area) |
Схема используемой памяти: |
...-7C00 стек |
7C00-7E00 код бутсектора |
7E00-8200 вспомогательный файл загрузчика (kordldr.f1x) |
8200-8300 список загруженных секторов таблицы FAT16 |
(1 = соответствующий сектор загружен) |
60000-80000 загруженная таблица FAT12 / место для таблицы FAT16 |
80000-90000 текущий кластер текущей рассматриваемой папки |
90000-92000 кэш для корневой папки |
92000-... кэш для некорневых папок (каждой папке отводится |
2000h байт = 100h входов, одновременно в кэше |
может находиться не более 7 папок; |
точный размер определяется размером доступной |
физической памяти - как правило, непосредственно |
перед A0000 размещается EBDA, Extended BIOS Data Area) |
|
===================================================================== |
|
Îñíîâíîé ïðîöåññ çàãðóçêè. |
Òî÷êà âõîäà (start): ïîëó÷àåò óïðàâëåíèå îò BIOS ïðè çàãðóçêå, ïðè ýòîì |
dl ñîäåðæèò èäåíòèôèêàòîð äèñêà, ñ êîòîðîãî èä¸ò çàãðóçêà |
1. Íàñòðàèâàåò ñòåê ss:sp = 0:7C00 (ñòåê ðàñïîëàãàåòñÿ íåïîñðåäñòâåííî ïåðåä |
êîäîì), ñåãìåíò äàííûõ ds = 0, è óñòàíàâëèâàåò ss:bp íà íà÷àëî |
áóòñåêòîðà (â äàëüíåéøåì äàííûå áóäóò àäðåñîâàòüñÿ ÷åðåç [bp+N] - |
ýòî îñâîáîæäàåò ds è ýêîíîìèò íà ðàçìåðå êîäà). |
2. LBA-âåðñèÿ: ïðîâåðÿåò, ïîääåðæèâàåò ëè íîñèòåëü LBA, âûçîâîì ôóíêöèè 41h |
ïðåðûâàíèÿ 13h. Åñëè íåò, ïåðåõîäèò íà êîä îáðàáîòêè îøèáîê ñ |
ñîîáùåíèåì îá îòñóòñòâèè LBA. |
CHS-âåðñèÿ: îïðåäåëÿåò ãåîìåòðèþ íîñèòåëÿ âûçîâîì ôóíêöèè 8 ïðåðûâàíèÿ 13h è |
çàïèñûâàåò ïîëó÷åííûå äàííûå ïîâåðõ BPB. Åñëè âûçîâ çàâåðøèëñÿ îøèáêîé, |
ïðåäïîëàãàåò óæå ñóùåñòâóþùèå äàííûå êîððåêòíûìè. |
3. Âû÷èñëÿåò íåêîòîðûå ïàðàìåòðû FAT-òîìà: íà÷àëüíûé ñåêòîð êîðíåâîé ïàïêè |
è íà÷àëüíûé ñåêòîð äàííûõ. Êëàä¸ò èõ â ñòåê; âïîñëåäñòâèè îíè |
âñåãäà áóäóò ëåæàòü â ñòåêå è àäðåñîâàòüñÿ ÷åðåç bp. |
4. Ñ÷èòûâàåò íà÷àëî êîðíåâîé ïàïêè ïî àäðåñó 9000:0000. ×èñëî ñ÷èòûâàåìûõ |
ñåêòîðîâ - ìèíèìóì èç ðàçìåðà êîðíåâîé ïàïêè, óêàçàííîãî â BPB, è 16 |
(ðàçìåð êýøà äëÿ êîðíåâîé ïàïêè - 2000h áàéò = 16 ñåêòîðîâ). |
5. Èùåò â êîðíåâîé ïàïêå ýëåìåíò kordldr.f1x. Åñëè íå íàõîäèò, èëè åñëè |
îí îêàçûâàåòñÿ ïàïêîé, èëè åñëè ôàéë èìååò íóëåâóþ äëèíó - |
ïåðåõîäèò íà êîä îáðàáîòêè îøèáîê ñ ñîîáùåíèåì î |
íåíàéäåííîì çàãðóç÷èêå. |
Çàìå÷àíèå: íà ýòîì ýòàïå çàãðóçêè èñêàòü ìîæíî òîëüêî â êîðíåâîé |
ïàïêå è òîëüêî èìåíà, çàäàííûå â ôîðìàòå ôàéëîâîé ñèñòåìå FAT |
(8+3 - 8 áàéò íà èìÿ, 3 áàéòà íà ðàñøèðåíèå, âñå áóêâû äîëæíû |
áûòü çàãëàâíûìè, ïðè íåîáõîäèìîñòè èìÿ è ðàñøèðåíèå äîïîëíÿþòñÿ |
ïðîáåëàìè, ðàçäåëÿþùåé òî÷êè íåò, çàâåðøàþùåãî íóëÿ íåò). |
6. Çàãðóæàåò ïåðâûé êëàñòåð ôàéëà kordldr.f1x ïî àäðåñó 0:7E00 è ïåðåäà¸ò |
åìó óïðàâëåíèå. Ïðè ýòîì â ðåãèñòðàõ dx:ax îêàçûâàåòñÿ àáñîëþòíûé |
íîìåð ïåðâîãî ñåêòîðà kordldr.f1x, à â cx - ÷èñëî ñ÷èòàííûõ ñåêòîðîâ |
(ðàâíîå ðàçìåðó êëàñòåðà). |
Основной процесс загрузки. |
Точка входа (start): получает управление от BIOS при загрузке, при этом |
dl содержит идентификатор диска, с которого идёт загрузка |
1. Настраивает стек ss:sp = 0:7C00 (стек располагается непосредственно перед |
кодом), сегмент данных ds = 0, и устанавливает ss:bp на начало |
бутсектора (в дальнейшем данные будут адресоваться через [bp+N] - |
это освобождает ds и экономит на размере кода). |
2. LBA-версия: проверяет, поддерживает ли носитель LBA, вызовом функции 41h |
прерывания 13h. Если нет, переходит на код обработки ошибок с |
сообщением об отсутствии LBA. |
CHS-версия: определяет геометрию носителя вызовом функции 8 прерывания 13h и |
записывает полученные данные поверх BPB. Если вызов завершился ошибкой, |
предполагает уже существующие данные корректными. |
3. Вычисляет некоторые параметры FAT-тома: начальный сектор корневой папки |
и начальный сектор данных. Кладёт их в стек; впоследствии они |
всегда будут лежать в стеке и адресоваться через bp. |
4. Считывает начало корневой папки по адресу 9000:0000. Число считываемых |
секторов - минимум из размера корневой папки, указанного в BPB, и 16 |
(размер кэша для корневой папки - 2000h байт = 16 секторов). |
5. Ищет в корневой папке элемент kordldr.f1x. Если не находит, или если |
он оказывается папкой, или если файл имеет нулевую длину - |
переходит на код обработки ошибок с сообщением о |
ненайденном загрузчике. |
Замечание: на этом этапе загрузки искать можно только в корневой |
папке и только имена, заданные в формате файловой системе FAT |
(8+3 - 8 байт на имя, 3 байта на расширение, все буквы должны |
быть заглавными, при необходимости имя и расширение дополняются |
пробелами, разделяющей точки нет, завершающего нуля нет). |
6. Загружает первый кластер файла kordldr.f1x по адресу 0:7E00 и передаёт |
ему управление. При этом в регистрах dx:ax оказывается абсолютный |
номер первого сектора kordldr.f1x, а в cx - число считанных секторов |
(равное размеру кластера). |
|
Âñïîìîãàòåëüíûå ïðîöåäóðû áóòñåêòîðà. |
Êîä îáðàáîòêè îøèáîê (err): |
1. Âûâîäèò ñòðîêó ñ ñîîáùåíèåì îá îøèáêå. |
2. Âûâîäèò ñòðîêó "Press any key...". |
3. Æä¸ò íàæàòèÿ any key. |
4. Âûçûâàåò int 18h, äàâàÿ øàíñ BIOSó ïîïûòàòüñÿ çàãðóçèòüñÿ îòêóäà-íèáóäü åù¸. |
5. Äëÿ ïîäñòðàõîâêè çàöèêëèâàåòñÿ. |
Вспомогательные процедуры бутсектора. |
Код обработки ошибок (err): |
1. Выводит строку с сообщением об ошибке. |
2. Выводит строку "Press any key...". |
3. Ждёт нажатия any key. |
4. Вызывает int 18h, давая шанс BIOSу попытаться загрузиться откуда-нибудь ещё. |
5. Для подстраховки зацикливается. |
|
Ïðîöåäóðà ÷òåíèÿ ñåêòîðîâ (read_sectors è read_sectors2): |
íà âõîäå äîëæíî áûòü óñòàíîâëåíî: |
Процедура чтения секторов (read_sectors и read_sectors2): |
на входе должно быть установлено: |
ss:bp = 0:7C00 |
es:bx = óêàçàòåëü íà íà÷àëî áóôåðà, êóäà áóäóò ïðî÷èòàíû äàííûå |
dx:ax = ñòàðòîâûé ñåêòîð (îòíîñèòåëüíî íà÷àëà ëîãè÷åñêîãî äèñêà |
äëÿ read_sectors, îòíîñèòåëüíî íà÷àëà äàííûõ äëÿ read_sectors2) |
cx = ÷èñëî ñåêòîðîâ (äîëæíî áûòü áîëüøå íóëÿ) |
íà âûõîäå: es:bx óêàçûâàåò íà êîíåö áóôåðà, â êîòîðûé áûëè ïðî÷èòàíû äàííûå |
0. Åñëè âûçûâàåòñÿ read_sectors2, îíà ïåðåâîäèò óêàçàííûé åé íîìåð ñåêòîðà |
â íîìåð îòíîñèòåëüíî íà÷àëà ëîãè÷åñêîãî äèñêà, ïðèáàâëÿÿ íîìåð ñåêòîðà |
íà÷àëà äàííûõ, õðàíÿùèéñÿ â ñòåêå êàê [bp-8]. |
1. Ïåðåâîäèò ñòàðòîâûé ñåêòîð (îòñ÷èòûâàåìûé îò íà÷àëà òîìà) â ñåêòîð íà |
óñòðîéñòâå, ïðèáàâëÿÿ çíà÷åíèå ñîîòâåòñòâóþùåãî ïîëÿ èç BPB. |
2.  öèêëå (øàãè 3-6) ÷èòàåò ñåêòîðû, ñëåäèò çà òåì, ÷òîáû íà êàæäîé èòåðàöèè |
CHS-âåðñèÿ: âñå ÷èòàåìûå ñåêòîðû áûëè íà îäíîé äîðîæêå. |
LBA-âåðñèÿ: ÷èñëî ÷èòàåìûõ ñåêòîðîâ íå ïðåâîñõîäèëî 7Fh (òðåáîâàíèå |
ñïåöèôèêàöèè EDD BIOS). |
CHS-âåðñèÿ: |
3. Ïåðåâîäèò àáñîëþòíûé íîìåð ñåêòîðà â CHS-ñèñòåìó: ñåêòîð ðàññ÷èòûâàåòñÿ êàê |
åäèíèöà ïëþñ îñòàòîê îò äåëåíèÿ àáñîëþòíîãî íîìåðà íà ÷èñëî ñåêòîðîâ |
íà äîðîæêå; äîðîæêà ðàññ÷èòûâàåòñÿ êàê îñòàòîê îò äåëåíèÿ ÷àñòíîãî, |
ïîëó÷åííîãî íà ïðåäûäóùåì øàãå, íà ÷èñëî äîðîæåê, à öèëèíäð - êàê |
÷àñòíîå îò ýòîãî æå äåëåíèÿ. Åñëè ÷èñëî ñåêòîðîâ äëÿ ÷òåíèÿ áîëüøå, |
÷åì ÷èñëî ñåêòîðîâ äî êîíöà äîðîæêè, óìåíüøàåò ÷èñëî ñåêòîðîâ äëÿ |
÷òåíèÿ. |
4. Ôîðìèðóåò äàííûå äëÿ âûçîâà int 13h (ah=2 - ÷òåíèå, al=÷èñëî ñåêòîðîâ, |
dh=ãîëîâêà, (ìëàäøèå 6 áèò cl)=ñåêòîð, |
(ñòàðøèå 2 áèòà cl è âåñü ch)=äîðîæêà, dl=äèñê, es:bx->áóôåð). |
5. Âûçûâàåò BIOS. Åñëè BIOS ðàïîðòóåò îá îøèáêå, âûïîëíÿåò ñáðîñ äèñêà |
è ïîâòîðÿåò ïîïûòêó ÷òåíèÿ, âñåãî äåëàåòñÿ íå áîëåå òð¸õ ïîïûòîê |
(íåñêîëüêî ïîïûòîê íóæíî â ñëó÷àå äèñêåòû äëÿ ãàðàíòèè òîãî, ÷òî |
ìîòîð ðàñêðóòèëñÿ). Åñëè âñå òðè ðàçà ïðîèñõîäèò îøèáêà ÷òåíèÿ, |
ïåðåõîäèò íà êîä îáðàáîòêè îøèáîê ñ ñîîáùåíèåì "Read error". |
6.  ñîîòâåòñòâèè ñ ÷èñëîì ïðî÷èòàííûõ íà òåêóùåé èòåðàöèè ñåêòîðîâ |
êîððåêòèðóåò òåêóùèé ñåêòîð, ÷èñëî îñòàâøèõñÿ ñåêòîðîâ è óêàçàòåëü íà |
áóôåð (â ïàðå es:bx êîððåêòèðóåòñÿ es). Åñëè âñ¸ ïðî÷èòàíî, çàêàí÷èâàåò |
ðàáîòó, èíà÷å âîçâðàùàåòñÿ íà øàã 3. |
LBA-âåðñèÿ: |
3. Åñëè ÷èñëî ñåêòîðîâ äëÿ ÷òåíèÿ áîëüøå 7Fh, óìåíüøàåò åãî (äëÿ òåêóùåé |
èòåðàöèè) äî 7Fh. |
4. Ôîðìèðóåò â ñòåêå ïàêåò äëÿ int 13h (êëàä¸ò âñå íóæíûå äàííûå êîìàíäàìè |
push, ïðè÷¸ì â îáðàòíîì ïîðÿäêå: ñòåê - ñòðóêòóðà LIFO, è äàííûå â |
ñòåêå õðàíÿòñÿ â îáðàòíîì ïîðÿäêå ïî îòíîøåíèþ ê òîìó, êàê èõ òóäà |
êëàëè). |
5. Âûçûâàåò BIOS. Åñëè BIOS ðàïîðòóåò îá îøèáêå, ïåðåõîäèò íà êîä îáðàáîòêè |
îøèáîê ñ ñîîáùåíèåì "Read error". Î÷èùàåò ñòåê îò ïàêåòà, |
ñôîðìèðîâàííîãî íà ïðåäûäóùåì øàãå. |
6.  ñîîòâåòñòâèè ñ ÷èñëîì ïðî÷èòàííûõ íà òåêóùåé èòåðàöèè ñåêòîðîâ |
êîððåêòèðóåò òåêóùèé ñåêòîð, ÷èñëî îñòàâøèõñÿ ñåêòîðîâ è óêàçàòåëü íà |
áóôåð (â ïàðå es:bx êîððåêòèðóåòñÿ es). Åñëè âñ¸ ïðî÷èòàíî, çàêàí÷èâàåò |
ðàáîòó, èíà÷å âîçâðàùàåòñÿ íà øàã 3. |
es:bx = указатель на начало буфера, куда будут прочитаны данные |
dx:ax = стартовый сектор (относительно начала логического диска |
для read_sectors, относительно начала данных для read_sectors2) |
cx = число секторов (должно быть больше нуля) |
на выходе: es:bx указывает на конец буфера, в который были прочитаны данные |
0. Если вызывается read_sectors2, она переводит указанный ей номер сектора |
в номер относительно начала логического диска, прибавляя номер сектора |
начала данных, хранящийся в стеке как [bp-8]. |
1. Переводит стартовый сектор (отсчитываемый от начала тома) в сектор на |
устройстве, прибавляя значение соответствующего поля из BPB. |
2. В цикле (шаги 3-6) читает секторы, следит за тем, чтобы на каждой итерации |
CHS-версия: все читаемые секторы были на одной дорожке. |
LBA-версия: число читаемых секторов не превосходило 7Fh (требование |
спецификации EDD BIOS). |
CHS-версия: |
3. Переводит абсолютный номер сектора в CHS-систему: сектор рассчитывается как |
единица плюс остаток от деления абсолютного номера на число секторов |
на дорожке; дорожка рассчитывается как остаток от деления частного, |
полученного на предыдущем шаге, на число дорожек, а цилиндр - как |
частное от этого же деления. Если число секторов для чтения больше, |
чем число секторов до конца дорожки, уменьшает число секторов для |
чтения. |
4. Формирует данные для вызова int 13h (ah=2 - чтение, al=число секторов, |
dh=головка, (младшие 6 бит cl)=сектор, |
(старшие 2 бита cl и весь ch)=дорожка, dl=диск, es:bx->буфер). |
5. Вызывает BIOS. Если BIOS рапортует об ошибке, выполняет сброс диска |
и повторяет попытку чтения, всего делается не более трёх попыток |
(несколько попыток нужно в случае дискеты для гарантии того, что |
мотор раскрутился). Если все три раза происходит ошибка чтения, |
переходит на код обработки ошибок с сообщением "Read error". |
6. В соответствии с числом прочитанных на текущей итерации секторов |
корректирует текущий сектор, число оставшихся секторов и указатель на |
буфер (в паре es:bx корректируется es). Если всё прочитано, заканчивает |
работу, иначе возвращается на шаг 3. |
LBA-версия: |
3. Если число секторов для чтения больше 7Fh, уменьшает его (для текущей |
итерации) до 7Fh. |
4. Формирует в стеке пакет для int 13h (кладёт все нужные данные командами |
push, причём в обратном порядке: стек - структура LIFO, и данные в |
стеке хранятся в обратном порядке по отношению к тому, как их туда |
клали). |
5. Вызывает BIOS. Если BIOS рапортует об ошибке, переходит на код обработки |
ошибок с сообщением "Read error". Очищает стек от пакета, |
сформированного на предыдущем шаге. |
6. В соответствии с числом прочитанных на текущей итерации секторов |
корректирует текущий сектор, число оставшихся секторов и указатель на |
буфер (в паре es:bx корректируется es). Если всё прочитано, заканчивает |
работу, иначе возвращается на шаг 3. |
|
Ïðîöåäóðà ïîèñêà ýëåìåíòà ïî èìåíè â óæå ïðî÷èòàííûõ äàííûõ ïàïêè |
Процедура поиска элемента по имени в уже прочитанных данных папки |
(scan_for_filename): |
íà âõîäå äîëæíî áûòü óñòàíîâëåíî: |
ds:si = óêàçàòåëü íà èìÿ ôàéëà â ôîðìàòå FAT (11 áàéò, 8 íà èìÿ, |
3 íà ðàñøèðåíèå, âñå áóêâû çàãëàâíûå, åñëè èìÿ/ðàñøèðåíèå |
êîðî÷å, îíî äîïîëíÿåòñÿ äî ìàêñèìóìà ïðîáåëàìè) |
es = ñåãìåíò äàííûõ ïàïêè |
cx = ÷èñëî ýëåìåíòîâ â ïðî÷èòàííûõ äàííûõ |
íà âûõîäå: ZF îïðåäåëÿåò, íóæíî ëè ïðîäîëæàòü ðàçáîð äàííûõ ïàïêè |
(ZF=1, åñëè ëèáî íàéäåí çàïðîøåííûé ýëåìåíò, ëèáî äîñòèãíóò |
êîíåö ïàïêè); CF îïðåäåëÿåò, óäàëîñü ëè íàéòè ýëåìåíò ñ èñêîìûì èìåíåì |
(CF=1, åñëè íå óäàëîñü); åñëè óäàëîñü, òî es:di óêàçûâàåò íà íåãî. |
scan_for_filename ñ÷èòàåò, ÷òî äàííûå ïàïêè ðàçìåùàþòñÿ íà÷èíàÿ ñ es:0. |
Ïåðâîé êîìàíäîé ïðîöåäóðà îáíóëÿåò di. Çàòåì ïðîñòî â öèêëå ïî ýëåìåíòàì ïàïêè |
ïðîâåðÿåò èìåíà. |
на входе должно быть установлено: |
ds:si = указатель на имя файла в формате FAT (11 байт, 8 на имя, |
3 на расширение, все буквы заглавные, если имя/расширение |
короче, оно дополняется до максимума пробелами) |
es = сегмент данных папки |
cx = число элементов в прочитанных данных |
на выходе: ZF определяет, нужно ли продолжать разбор данных папки |
(ZF=1, если либо найден запрошенный элемент, либо достигнут |
конец папки); CF определяет, удалось ли найти элемент с искомым именем |
(CF=1, если не удалось); если удалось, то es:di указывает на него. |
scan_for_filename считает, что данные папки размещаются начиная с es:0. |
Первой командой процедура обнуляет di. Затем просто в цикле по элементам папки |
проверяет имена. |
|
Ïðîöåäóðà ïîèñêà ýëåìåíòà â êîðíåâîé ïàïêå (lookup_in_root_dir): |
íà âõîäå äîëæíî áûòü óñòàíîâëåíî: |
Процедура поиска элемента в корневой папке (lookup_in_root_dir): |
на входе должно быть установлено: |
ss:bp = 0:7C00 |
ds:si = óêàçàòåëü íà èìÿ ôàéëà â ôîðìàòå FAT (ñì. âûøå) |
íà âûõîäå: ôëàã CF îïðåäåëÿåò, óäàëîñü ëè íàéòè ôàéë; åñëè óäàëîñü, òî |
CF ñáðîøåí è es:di óêàçûâàåò íà ýëåìåíò ïàïêè |
Íà÷èíàåò ñ ïðîñìîòðà êýøèðîâàííîé (íà÷àëüíîé) ÷àñòè êîðíåâîé ïàïêè.  öèêëå |
ñêàíèðóåò ýëåìåíòû; åñëè ïî ðåçóëüòàòàì ñêàíèðîâàíèÿ îáíàðóæèâàåò, |
÷òî íóæíî ÷èòàòü ïàïêó äàëüøå, òî ñ÷èòûâàåò íå áîëåå 0x10000 = 64K |
áàéò (îãðàíè÷åíèå ââåäåíî ïî äâóì ïðè÷èíàì: âî-ïåðâûõ, ÷òîáû çàâåäîìî |
íå âûëåçòè çà ïðåäåëû èñïîëüçóåìîé ïàìÿòè, âî-âòîðûõ, ñêàíèðîâàíèå |
ïðåäïîëàãàåò, ÷òî âñå îáðàáàòûâàåìûå ýëåìåíòû ðàñïîëàãàþòñÿ â îäíîì |
ñåãìåíòå) è ïðîäîëæàåò öèêë. |
Ñêàíèðîâàíèå ïðåêðàùàåòñÿ â òð¸õ ñëó÷àÿõ: îáíàðóæåí èñêîìûé ýëåìåíò; |
êîí÷èëèñü ýëåìåíòû â ïàïêå (ñóäÿ ïî ÷èñëó ýëåìåíòîâ, óêàçàííîìó â BPB); |
î÷åðåäíîé ýëåìåíò ïàïêè ñèãíàëèçèðóåò î êîíöå (ïåðâûé áàéò íóëåâîé). |
ds:si = указатель на имя файла в формате FAT (см. выше) |
на выходе: флаг CF определяет, удалось ли найти файл; если удалось, то |
CF сброшен и es:di указывает на элемент папки |
Начинает с просмотра кэшированной (начальной) части корневой папки. В цикле |
сканирует элементы; если по результатам сканирования обнаруживает, |
что нужно читать папку дальше, то считывает не более 0x10000 = 64K |
байт (ограничение введено по двум причинам: во-первых, чтобы заведомо |
не вылезти за пределы используемой памяти, во-вторых, сканирование |
предполагает, что все обрабатываемые элементы располагаются в одном |
сегменте) и продолжает цикл. |
Сканирование прекращается в трёх случаях: обнаружен искомый элемент; |
кончились элементы в папке (судя по числу элементов, указанному в BPB); |
очередной элемент папки сигнализирует о конце (первый байт нулевой). |
|
Ïðîöåäóðà âûâîäà íà ýêðàí ASCIIZ-ñòðîêè (out_string): |
íà âõîäå: ds:si -> ñòðîêà |
 öèêëå, ïîêà íå äîñòèãíóò çàâåðøàþùèé íîëü, âûçûâàåò ôóíêöèþ int 10h/ah=0Eh. |
Процедура вывода на экран ASCIIZ-строки (out_string): |
на входе: ds:si -> строка |
В цикле, пока не достигнут завершающий ноль, вызывает функцию int 10h/ah=0Eh. |
|
===================================================================== |
|
Ðàáîòà âñïîìîãàòåëüíîãî çàãðóç÷èêà kordldr.f1x: |
1. Îïðåäåëÿåò, áûë ëè îí çàãðóæåí CHS- èëè LBA-âåðñèåé áóòñåêòîðà. |
 çàâèñèìîñòè îò ýòîãî óñòàíàâëèâàåò ñìåùåíèÿ èñïîëüçóåìûõ ïðîöåäóð |
áóòñåêòîðà. Êðèòåðèé ïðîâåðêè: scan_for_filename äîëæíà íà÷èíàòüñÿ |
ñ èíñòðóêöèè 'xor di,di' ñ êîäîì 31 FF (âîîáùå-òî ýòà èíñòðóêöèÿ ìîæåò |
ñ ðàâíûì óñïåõîì àññåìáëèðîâàòüñÿ è êàê 33 FF, íî fasm ãåíåðèðóåò |
èìåííî òàêóþ ôîðìó). |
2. Óçíà¸ò ðàçìåð ñâîáîäíîé áàçîâîé ïàìÿòè (ò.å. ñâîáîäíîãî íåïðåðûâíîãî êóñêà |
àäðåñîâ ïàìÿòè, íà÷èíàþùåãîñÿ ñ 0) âûçîâîì int 12h.  ñîîòâåòñòâèè ñ |
íèì âû÷èñëÿåò ÷èñëî ýëåìåíòîâ â êýøå ïàïîê. Õîòÿ áû äëÿ îäíîãî ýëåìåíòà |
ìåñòî äîëæíî áûòü, îòñþäà îãðàíè÷åíèå â 592 Kb (94000h áàéò). |
Çàìå÷àíèå: ýòîò ðàçìåð íå ìîæåò ïðåâîñõîäèòü 0A0000h áàéò è |
íà ïðàêòèêå îêàçûâàåòñÿ íåìíîãî (íà 1-2 êèëîáàéòà) ìåíüøèì èç-çà |
íàëè÷èÿ äîïîëíèòåëüíîé îáëàñòè äàííûõ BIOS "ââåðõó" áàçîâîé ïàìÿòè. |
3. Îïðåäåëÿåò òèï ôàéëîâîé ñèñòåìû: FAT12 èëè FAT16. Ñîãëàñíî îôèöèàëüíîé |
ñïåöèôèêàöèè îò Microsoft (âåðñèÿ 1.03 ñïåöèôèêàöèè äàòèðîâàíà, |
ê ñëîâó, 06 äåêàáðÿ 2000 ãîäà), ðàçðÿäíîñòü FAT îïðåäåëÿåòñÿ |
èñêëþ÷èòåëüíî ÷èñëîì êëàñòåðîâ: ìàêñèìàëüíîå ÷èñëî êëàñòåðîâ íà |
FAT12-òîìå ðàâíî 4094 = 0xFF4. Ñîãëàñíî çäðàâîìó ñìûñëó, íà FAT12 |
ìîæåò áûòü 0xFF5 êëàñòåðîâ, íî íå áîëüøå: êëàñòåðû íóìåðóþòñÿ ñ 2, |
à ÷èñëî 0xFF7 íå ìîæåò áûòü êîððåêòíûì íîìåðîì êëàñòåðà. |
Win95/98/Me ñëåäóåò çäðàâîìó ñìûñëó: ðàçãðàíè÷åíèå FAT12/16 äåëàåòñÿ |
ïî ìàêñèìóìó 0xFF5. Äðàéâåð FAT â WinNT/2k/XP/Vista âîîáùå ïîñòóïàåò |
ÿâíî íåâåðíî, ñ÷èòàÿ, ÷òî 0xFF6 (èëè ìåíüøå) êëàñòåðîâ îçíà÷àåò |
FAT12-òîì, â ðåçóëüòàòå ïîëó÷àåòñÿ, ÷òî ïîñëåäíèé êëàñòåð |
(â ñëó÷àå 0xFF6) íåàäðåñóåì. Îñíîâíîé çàãðóç÷èê osloader.exe |
[âñòðîåí â ntldr] äëÿ NT/2k/XP äåëàåò òàê æå. Ïåðâè÷íûé çàãðóç÷èê |
[áóòñåêòîð FAT12/16 çàãðóæàåò ïåðâûé ñåêòîð ntldr, è ðàçáîð FAT-òàáëèöû |
ëåæèò íà í¸ì] â NT/2k ïîäâåðæåí òîé æå îøèáêå.  XP å¸ òàêè èñïðàâèëè |
â ñîîòâåòñòâèè ñî ñïåöèôèêàöèåé. Linux ïðè îïðåäåëåíèè FAT12/FAT16 |
÷åñòíî ñëåäóåò ñïåöèôèêàöèè. |
Çäåñü êîä îñíîâàí âñ¸ æå íà ñïåöèôèêàöèè. 9x ìåðòâà, à â ëèíåéêå NT |
Microsoft åñëè è áóäåò èñïðàâëÿòü îøèáêè, òî ñîãëàñíî ñîáñòâåííîìó |
îïèñàíèþ. |
4. Äëÿ FAT12: çàãðóæàåò â ïàìÿòü ïåðâóþ êîïèþ òàáëèöû FAT ïî àäðåñó 6000:0000. |
Åñëè ðàçìåð, óêàçàííûé â BPB, ïðåâîñõîäèò 12 ñåêòîðîâ, |
ýòî îçíà÷àåò, ÷òî çàÿâëåííûé ðàçìåð ñëèøêîì áîëüøîé (ýòî íå ñ÷èòàåòñÿ |
îøèáêîé ôàéëîâîé ñèñòåìû), è ÷èòàþòñÿ òîëüêî 12 ñåêòîðîâ (òàáëèöà FAT12 |
çàâåäîìî âëåçàåò â òàêîé îáú¸ì äàííûõ). |
Äëÿ FAT16: èíèöèàëèçèðóåò âíóòðåííèå äàííûå, óêàçûâàÿ, ÷òî íèêàêîé ñåêòîð |
FAT íå çàãðóæåí (îíè áóäóò ïîäãðóæàòüñÿ ïîçäíåå, êîãäà ïîíàäîáÿòñÿ |
è òîëüêî òå, êîòîðûå ïîíàäîáÿòñÿ). |
5. Åñëè êëàñòåð ðàâåí ñåêòîðó, òî áóòñåêòîð çàãðóçèë òîëüêî ÷àñòü ôàéëà |
kordldr.f1x, è çàãðóç÷èê ïîäãðóæàåò âòîðóþ ñâîþ ÷àñòü, èñïîëüçóÿ |
çíà÷åíèÿ ðåãèñòðîâ íà âõîäå â kordldr.f1x. |
6. Çàãðóæàåò âòîðè÷íûé çàãðóç÷èê kord/loader ïî àäðåñó 1000:0000. Åñëè ôàéë íå |
íàéäåí, èëè îêàçàëñÿ ïàïêîé, èëè îêàçàëñÿ ñëèøêîì áîëüøèì, òî ïåðåõîäèò |
íà êîä îáðàáîòêè îøèáîê èç áóòñåêòîðà ñ ñîîáùåíèåì |
Работа вспомогательного загрузчика kordldr.f1x: |
1. Определяет, был ли он загружен CHS- или LBA-версией бутсектора. |
В зависимости от этого устанавливает смещения используемых процедур |
бутсектора. Критерий проверки: scan_for_filename должна начинаться |
с инструкции 'xor di,di' с кодом 31 FF (вообще-то эта инструкция может |
с равным успехом ассемблироваться и как 33 FF, но fasm генерирует |
именно такую форму). |
2. Узнаёт размер свободной базовой памяти (т.е. свободного непрерывного куска |
адресов памяти, начинающегося с 0) вызовом int 12h. В соответствии с |
ним вычисляет число элементов в кэше папок. Хотя бы для одного элемента |
место должно быть, отсюда ограничение в 592 Kb (94000h байт). |
Замечание: этот размер не может превосходить 0A0000h байт и |
на практике оказывается немного (на 1-2 килобайта) меньшим из-за |
наличия дополнительной области данных BIOS "вверху" базовой памяти. |
3. Определяет тип файловой системы: FAT12 или FAT16. Согласно официальной |
спецификации от Microsoft (версия 1.03 спецификации датирована, |
к слову, 06 декабря 2000 года), разрядность FAT определяется |
исключительно числом кластеров: максимальное число кластеров на |
FAT12-томе равно 4094 = 0xFF4. Согласно здравому смыслу, на FAT12 |
может быть 0xFF5 кластеров, но не больше: кластеры нумеруются с 2, |
а число 0xFF7 не может быть корректным номером кластера. |
Win95/98/Me следует здравому смыслу: разграничение FAT12/16 делается |
по максимуму 0xFF5. Драйвер FAT в WinNT/2k/XP/Vista вообще поступает |
явно неверно, считая, что 0xFF6 (или меньше) кластеров означает |
FAT12-том, в результате получается, что последний кластер |
(в случае 0xFF6) неадресуем. Основной загрузчик osloader.exe |
[встроен в ntldr] для NT/2k/XP делает так же. Первичный загрузчик |
[бутсектор FAT12/16 загружает первый сектор ntldr, и разбор FAT-таблицы |
лежит на нём] в NT/2k подвержен той же ошибке. В XP её таки исправили |
в соответствии со спецификацией. Linux при определении FAT12/FAT16 |
честно следует спецификации. |
Здесь код основан всё же на спецификации. 9x мертва, а в линейке NT |
Microsoft если и будет исправлять ошибки, то согласно собственному |
описанию. |
4. Для FAT12: загружает в память первую копию таблицы FAT по адресу 6000:0000. |
Если размер, указанный в BPB, превосходит 12 секторов, |
это означает, что заявленный размер слишком большой (это не считается |
ошибкой файловой системы), и читаются только 12 секторов (таблица FAT12 |
заведомо влезает в такой объём данных). |
Для FAT16: инициализирует внутренние данные, указывая, что никакой сектор |
FAT не загружен (они будут подгружаться позднее, когда понадобятся |
и только те, которые понадобятся). |
5. Если кластер равен сектору, то бутсектор загрузил только часть файла |
kordldr.f1x, и загрузчик подгружает вторую свою часть, используя |
значения регистров на входе в kordldr.f1x. |
6. Загружает вторичный загрузчик kord/loader по адресу 1000:0000. Если файл не |
найден, или оказался папкой, или оказался слишком большим, то переходит |
на код обработки ошибок из бутсектора с сообщением |
"Fatal error: cannot load the secondary loader". |
Çàìå÷àíèå: íà ýòîì ýòàïå èìÿ ôàéëà óæå ìîæíî óêàçûâàòü âìåñòå ñ ïóò¸ì |
è â ôîðìàòå ASCIIZ, õîòÿ ïîääåðæêè äëèííûõ èì¸í è íåàíãëèéñêèõ ñèìâîëîâ |
ïî-ïðåæíåìó íåò. |
7. Èçìåíÿåò êîä îáðàáîòêè îøèáîê áóòñåêòîðà íà ïåðåõîä íà ìåòêó hooked_err. |
Ýòî íóæíî, ÷òîáû ïîñëåäóþùèå îáðàùåíèÿ ê êîäó áóòñåêòîðà â ñëó÷àå |
îøèáîê ÷òåíèÿ íå âûâîäèë ñîîòâåòñòâóþùåå ñîîáùåíèå ñ ïîñëåäóþùåé |
ïåðåçàãðóçêîé, à ðàïîðòîâàë îá îøèáêå ÷òåíèÿ, êîòîðóþ ìîã áû |
êàê-íèáóäü îáðàáîòàòü âòîðè÷íûé çàãðóç÷èê. |
8. Åñëè çàãðóçî÷íûé äèñê èìååò èäåíòèôèêàòîð ìåíüøå 0x80, |
òî óñòàíàâëèâàåò al='f' ("floppy"), ah=èäåíòèôèêàòîð äèñêà, |
èíà÷å al='h' ("hard"), ah=èäåíòèôèêàòîð äèñêà-0x80 (íîìåð äèñêà). |
Óñòàíàâëèâàåò bx='12', åñëè òèï ôàéëîâîé ñèñòåìû - FAT12, è |
bx='16' â ñëó÷àå FAT16. Óñòàíàâëèâàåò si=ñìåùåíèå ôóíêöèè îáðàòíîãî |
âûçîâà. Ïîñêîëüêó â ýòîò ìîìåíò ds=0, òî ds:si îáðàçóþò ïîëíûé àäðåñ. |
9. Ïåðåäà¸ò óïðàâëåíèå ïî àäðåñó 1000:0000. |
Замечание: на этом этапе имя файла уже можно указывать вместе с путём |
и в формате ASCIIZ, хотя поддержки длинных имён и неанглийских символов |
по-прежнему нет. |
7. Изменяет код обработки ошибок бутсектора на переход на метку hooked_err. |
Это нужно, чтобы последующие обращения к коду бутсектора в случае |
ошибок чтения не выводил соответствующее сообщение с последующей |
перезагрузкой, а рапортовал об ошибке чтения, которую мог бы |
как-нибудь обработать вторичный загрузчик. |
8. Если загрузочный диск имеет идентификатор меньше 0x80, |
то устанавливает al='f' ("floppy"), ah=идентификатор диска, |
иначе al='h' ("hard"), ah=идентификатор диска-0x80 (номер диска). |
Устанавливает bx='12', если тип файловой системы - FAT12, и |
bx='16' в случае FAT16. Устанавливает si=смещение функции обратного |
вызова. Поскольку в этот момент ds=0, то ds:si образуют полный адрес. |
9. Передаёт управление по адресу 1000:0000. |
|
Ôóíêöèÿ îáðàòíîãî âûçîâà äëÿ âòîðè÷íîãî çàãðóç÷èêà: |
ïðåäîñòàâëÿåò âîçìîæíîñòü ÷òåíèÿ ôàéëà. |
Âõîä è âûõîä îïèñàíû â ñïåöèôèêàöèè íà çàãðóç÷èê. |
1. Ñîõðàíÿåò ñòåê âûçûâàþùåãî êîäà è óñòàíàâëèâàåò ñâîé ñòåê: |
ss:sp = 0:(7C00-8), bp=7C00: ïàðà ss:bp ïðè ðàáîòå ñ îñòàëüíûì |
êîäîì äîëæíà óêàçûâàòü íà 0:7C00, à -8 áåð¸òñÿ îò òîãî, ÷òî |
èíèöèàëèçèðóþùèé êîä áóòñåêòîðà óæå ïîìåñòèë â ñòåê 2 äâîéíûõ ñëîâà, |
è îíè äîëæíû ñîõðàíÿòüñÿ â íåèçìåííîñòè. |
2. Ðàçáèðàåò ïåðåäàííûå ïàðàìåòðû, âûÿñíÿåò, êàêîå äåéñòâèå çàïðîøåíî, |
è âûçûâàåò íóæíóþ âñïîìîãàòåëüíóþ ïðîöåäóðó. |
3. Âîññòàíàâëèâàåò ñòåê âûçûâàþùåãî êîäà è âîçâðàùàåò óïðàâëåíèå. |
Функция обратного вызова для вторичного загрузчика: |
предоставляет возможность чтения файла. |
Вход и выход описаны в спецификации на загрузчик. |
1. Сохраняет стек вызывающего кода и устанавливает свой стек: |
ss:sp = 0:(7C00-8), bp=7C00: пара ss:bp при работе с остальным |
кодом должна указывать на 0:7C00, а -8 берётся от того, что |
инициализирующий код бутсектора уже поместил в стек 2 двойных слова, |
и они должны сохраняться в неизменности. |
2. Разбирает переданные параметры, выясняет, какое действие запрошено, |
и вызывает нужную вспомогательную процедуру. |
3. Восстанавливает стек вызывающего кода и возвращает управление. |
|
Âñïîìîãàòåëüíûå ïðîöåäóðû kordldr.f1x. |
Ïðîöåäóðà ïîëó÷åíèÿ ñëåäóþùåãî êëàñòåðà â FAT (get_next_cluster): |
1. Âñïîìèíàåò ðàçðÿäíîñòü FAT, âû÷èñëåííóþ ðàíåå. |
Äëÿ FAT12: |
2. Óñòàíàâëèâàåò ds = 0x6000 - ñåãìåíò, êóäà ðàíåå áûëà ñ÷èòàíà |
âñÿ òàáëèöà FAT. |
3. Ïîäñ÷èòûâàåò si = (êëàñòåð) + (êëàñòåð)/2 - ñìåùåíèå â ýòîì ñåãìåíòå |
ñëîâà, çàäàþùåãî ñëåäóþùèé êëàñòåð. Çàãðóæàåò ñëîâî ïî ýòîìó àäðåñó. |
4. Åñëè êëàñòåð èìååò íå÷¸òíûé íîìåð, òî ñîîòâåòñòâóþùèé åìó ýëåìåíò |
ðàñïîëàãàåòñÿ â ñòàðøèõ 12 áèòàõ ñëîâà, è ñëîâî íóæíî ñäâèíóòü âïðàâî |
íà 4 áèòà; â ïðîòèâíîì ñëó÷àå - â ìëàäøèõ 12 áèòàõ, è äåëàòü íè÷åãî íå |
íàäî. |
5. Âûäåëÿåò èç ïîëó÷èâøåãîñÿ ñëîâà 12 áèò. Ñðàâíèâàåò èõ ñ ïðåäåëîì 0xFF7: |
íîìåðà íîðìàëüíûõ êëàñòåðîâ ìåíüøå, è ôëàã CF óñòàíàâëèâàåòñÿ; |
ñïåöèàëüíûå çíà÷åíèÿ EOF è BadClus ñáðàñûâàþò ôëàã CF. |
Äëÿ FAT16: |
2. Âû÷èñëÿåò àäðåñ ïàìÿòè, ïðåäíàçíà÷åííîé äëÿ ñîîòâåòñòâóþùåãî ñåêòîðà äàííûõ |
â òàáëèöå FAT. |
3. Åñëè ñåêòîð åù¸ íå çàãðóæåí, òî çàãðóæàåò åãî. |
4. Âû÷èñëÿåò ñìåùåíèå äàííûõ äëÿ êîíêðåòíîãî êëàñòåðà îòíîñèòåëüíî íà÷àëà |
ñåêòîðà. |
5. Çàãðóæàåò ñëîâî â ax èç àäðåñà, âû÷èñëåííîìó íà øàãàõ 1 è 3. |
6. Ñðàâíèâàåò åãî ñ ïðåäåëîì 0xFFF7: íîìåðà íîðìàëüíûõ êëàñòåðîâ ìåíüøå, è ôëàã |
CF óñòàíàâëèâàåòñÿ; ñïåöèàëüíûå çíà÷åíèÿ EOF è BadClus ñáðàñûâàþò CF. |
Вспомогательные процедуры kordldr.f1x. |
Процедура получения следующего кластера в FAT (get_next_cluster): |
1. Вспоминает разрядность FAT, вычисленную ранее. |
Для FAT12: |
2. Устанавливает ds = 0x6000 - сегмент, куда ранее была считана |
вся таблица FAT. |
3. Подсчитывает si = (кластер) + (кластер)/2 - смещение в этом сегменте |
слова, задающего следующий кластер. Загружает слово по этому адресу. |
4. Если кластер имеет нечётный номер, то соответствующий ему элемент |
располагается в старших 12 битах слова, и слово нужно сдвинуть вправо |
на 4 бита; в противном случае - в младших 12 битах, и делать ничего не |
надо. |
5. Выделяет из получившегося слова 12 бит. Сравнивает их с пределом 0xFF7: |
номера нормальных кластеров меньше, и флаг CF устанавливается; |
специальные значения EOF и BadClus сбрасывают флаг CF. |
Для FAT16: |
2. Вычисляет адрес памяти, предназначенной для соответствующего сектора данных |
в таблице FAT. |
3. Если сектор ещё не загружен, то загружает его. |
4. Вычисляет смещение данных для конкретного кластера относительно начала |
сектора. |
5. Загружает слово в ax из адреса, вычисленному на шагах 1 и 3. |
6. Сравнивает его с пределом 0xFFF7: номера нормальных кластеров меньше, и флаг |
CF устанавливается; специальные значения EOF и BadClus сбрасывают CF. |
|
Ïðîöåäóðà çàãðóçêè ôàéëà (load_file): |
1. Òåêóùàÿ ðàññìàòðèâàåìàÿ ïàïêà - êîðíåâàÿ. Â öèêëå âûïîëíÿåò øàãè 2-4. |
2. Êîíâåðòèðóåò èìÿ òåêóùåãî ðàññìàòðèâàåìîãî êîìïîíåíòà èìåíè (êîìïîíåíòû |
ðàçäåëÿþòñÿ ñèìâîëîì '/') â FAT-ôîðìàò 8+3. Åñëè ýòî íåâîçìîæíî |
(áîëüøå 8 ñèìâîëîâ â èìåíè, áîëüøå 3 ñèìâîëîâ â ðàñøèðåíèè èëè |
áîëüøå îäíîé òî÷êè), âîçâðàùàåòñÿ ñ îøèáêîé. |
3. Èùåò ýëåìåíò ñ òàêèì èìåíåì â òåêóùåé ðàññìàòðèâàåìîé ïàïêå. Äëÿ êîðíåâîé |
ïàïêè èñïîëüçóåòñÿ ïðîöåäóðà èç áóòñåêòîðà. Äëÿ îñòàëüíûõ ïàïîê: |
a) Ïðîâåðÿåò, åñòü ëè òàêàÿ ïàïêà â êýøå íåêîðíåâûõ ïàïîê. |
(Èäåíòèôèêàöèÿ ïàïîê îñóùåñòâëÿåòñÿ ïî íîìåðó íà÷àëüíîãî êëàñòåðà.) |
Åñëè òàêîé ïàïêè åù¸ íåò, äîáàâëÿåò å¸ â êýø; åñëè òîò ïåðåïîëíÿåòñÿ, |
âûêèäûâàåò ïàïêó, ê êîòîðîé äîëüøå âñåãî íå áûëî îáðàùåíèé. (Äëÿ |
êàæäîãî ýëåìåíòà êýøà õðàíèòñÿ ìåòêà îò 0 äî (ðàçìåð êýøà)-1, |
îïðåäåëÿþùàÿ åãî íîìåð ïðè ñîðòèðîâêå ïî äàâíîñòè ïîñëåäíåãî îáðàùåíèÿ. |
Ïðè îáðàùåíèè ê êàêîìó-òî ýëåìåíòó åãî ìåòêà ñòàíîâèòñÿ íóëåâîé, |
à òå ìåòêè, êîòîðûå ìåíüøå ñòàðîãî çíà÷åíèÿ, óâåëè÷èâàþòñÿ íà åäèíèöó.) |
á) Ïðîñìàòðèâàåò â ïîèñêàõ çàïðîøåííîãî èìåíè âñå ýëåìåíòû èç êýøà, |
èñïîëüçóÿ ïðîöåäóðó èç áóòñåêòîðà. Åñëè îáíàðóæèâàåò èñêîìûé ýëåìåíò, |
ïåðåõîäèò ê øàãó 4. Åñëè îáíàðóæèâàåò êîíåö ïàïêè, âîçâðàùàåòñÿ èç |
ïðîöåäóðû ñ îøèáêîé. |
â)  öèêëå ñ÷èòûâàåò ïàïêó ïîñåêòîðíî. Ïðè ýòîì ïðîïóñêàåò íà÷àëüíûå |
ñåêòîðû, êîòîðûå óæå íàõîäÿòñÿ â êýøå è óæå áûëè ïðîñìîòðåíû. Êàæäûé |
ïðî÷èòàííûé ñåêòîð êîïèðóåò â êýø, åñëè òàì åù¸ îñòà¸òñÿ ìåñòî, |
è ïðîñìàòðèâàåò â í¸ì âñå ýëåìåíòû. Ðàáîòàåò, ïîêà íå ñëó÷èòñÿ îäíî èç |
òð¸õ ñîáûòèé: íàéäåí èñêîìûé ýëåìåíò; êîí÷èëèñü êëàñòåðû (ñóäÿ ïî |
öåïî÷êå êëàñòåðîâ â FAT); î÷åðåäíîé ýëåìåíò ïàïêè ñèãíàëèçèðóåò î êîíöå |
(ïåðâûé áàéò íóëåâîé).  äâóõ ïîñëåäíèõ ñëó÷àÿõ âîçâðàùàåòñÿ ñ îøèáêîé. |
4. Ïðîâåðÿåò òèï íàéäåííîãî ýëåìåíòà (ôàéë/ïàïêà): ïîñëåäíèé ýëåìåíò â |
çàïðîøåííîì èìåíè äîëæåí áûòü ôàéëîì, âñå ïðîìåæóòî÷íûå - ïàïêàìè. |
Åñëè òåêóùèé êîìïîíåíò èìåíè - ïðîìåæóòî÷íûé, ïðîäâèãàåò òåêóùóþ |
ðàññìàòðèâàåìóþ ïàïêó è âîçâðàùàåòñÿ ê ïóíêòó 2. |
5. Ïðîõîäèò ïî öåïî÷êå êëàñòåðîâ â FAT è ñ÷èòûâàåò âñå êëàñòåðû â óêàçàííûé |
ïðè âûçîâå áóôåð ïîñëåäîâàòåëüíûìè âûçîâàìè ôóíêöèè áóòñåêòîðà; |
ïðè ýòîì åñëè íåñêîëüêî êëàñòåðîâ ôàéëà ðàñïîëîæåíû íà äèñêå |
ïîñëåäîâàòåëüíî, òî èõ ÷òåíèå îáúåäèíÿåòñÿ â îäíó îïåðàöèþ. |
Ñëåäèò çà òåì, ÷òîáû íå ïðåâûñèòü óêàçàííûé ïðè âûçîâå ïðîöåäóðû |
ëèìèò ÷èñëà ñåêòîðîâ äëÿ ÷òåíèÿ. |
Процедура загрузки файла (load_file): |
1. Текущая рассматриваемая папка - корневая. В цикле выполняет шаги 2-4. |
2. Конвертирует имя текущего рассматриваемого компонента имени (компоненты |
разделяются символом '/') в FAT-формат 8+3. Если это невозможно |
(больше 8 символов в имени, больше 3 символов в расширении или |
больше одной точки), возвращается с ошибкой. |
3. Ищет элемент с таким именем в текущей рассматриваемой папке. Для корневой |
папки используется процедура из бутсектора. Для остальных папок: |
a) Проверяет, есть ли такая папка в кэше некорневых папок. |
(Идентификация папок осуществляется по номеру начального кластера.) |
Если такой папки ещё нет, добавляет её в кэш; если тот переполняется, |
выкидывает папку, к которой дольше всего не было обращений. (Для |
каждого элемента кэша хранится метка от 0 до (размер кэша)-1, |
определяющая его номер при сортировке по давности последнего обращения. |
При обращении к какому-то элементу его метка становится нулевой, |
а те метки, которые меньше старого значения, увеличиваются на единицу.) |
б) Просматривает в поисках запрошенного имени все элементы из кэша, |
используя процедуру из бутсектора. Если обнаруживает искомый элемент, |
переходит к шагу 4. Если обнаруживает конец папки, возвращается из |
процедуры с ошибкой. |
в) В цикле считывает папку посекторно. При этом пропускает начальные |
секторы, которые уже находятся в кэше и уже были просмотрены. Каждый |
прочитанный сектор копирует в кэш, если там ещё остаётся место, |
и просматривает в нём все элементы. Работает, пока не случится одно из |
трёх событий: найден искомый элемент; кончились кластеры (судя по |
цепочке кластеров в FAT); очередной элемент папки сигнализирует о конце |
(первый байт нулевой). В двух последних случаях возвращается с ошибкой. |
4. Проверяет тип найденного элемента (файл/папка): последний элемент в |
запрошенном имени должен быть файлом, все промежуточные - папками. |
Если текущий компонент имени - промежуточный, продвигает текущую |
рассматриваемую папку и возвращается к пункту 2. |
5. Проходит по цепочке кластеров в FAT и считывает все кластеры в указанный |
при вызове буфер последовательными вызовами функции бутсектора; |
при этом если несколько кластеров файла расположены на диске |
последовательно, то их чтение объединяется в одну операцию. |
Следит за тем, чтобы не превысить указанный при вызове процедуры |
лимит числа секторов для чтения. |
|
Ïðîöåäóðà ïðîäîëæåíèÿ çàãðóçêè ôàéëà (continue_load_file): âñòðîåíà |
âíóòðü øàãà 5 load_file; çàãðóæàåò â ðåãèñòðû íóæíûå çíà÷åíèÿ (ðàíåå |
ñîõðàí¸ííûå èç load_file) è ïðîäîëæàåò øàã 5. |
Процедура продолжения загрузки файла (continue_load_file): встроена |
внутрь шага 5 load_file; загружает в регистры нужные значения (ранее |
сохранённые из load_file) и продолжает шаг 5. |