/kernel/branches/Kolibri-acpi/bootloader/extended_primary_loader/after_win/kordldr.win.txt |
---|
24,368 → 24,368 |
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
;***************************************************************************** |
Íåò ïîâåñòè ïå÷àëüíåå íà ñâåòå, |
×åì ïîâåñòü î çàêëèíèâøåì Reset'å... |
Нет повести печальнее на свете, |
Чем повесть о заклинившем Reset'е... |
Çàãðóç÷èê äëÿ FAT- è NTFS-òîìîâ äëÿ ñëó÷àåâ, êîãäà îñíîâíîé áóòñåêòîð çàãðóæàåò |
Windows, äëÿ íîñèòåëåé ñ ðàçìåðîì ñåêòîðà 512 áàéò. |
Загрузчик для FAT- и NTFS-томов для случаев, когда основной бутсектор загружает |
Windows, для носителей с размером сектора 512 байт. |
===================================================================== |
Òðåáîâàíèÿ äëÿ ðàáîòû: |
1) Âñå èñïîëüçóåìûå ôàéëû äîëæíû áûòü ÷èòàáåëüíû. |
2) Ìèíèìàëüíûé ïðîöåññîð - 80386. |
3) Â ñèñòåìå äîëæíî áûòü êàê ìèíèìóì 592K ñâîáîäíîé áàçîâîé ïàìÿòè. |
4) Ïóòè ê èñïîëüçóåìûì ôàéëàì íå äîëæíû ñîäåðæàòü ñèìâîëè÷åñêèõ ññûëîê NTFS |
(æ¸ñòêèå ññûëêè äîïóñêàþòñÿ). |
5) Èñïîëüçóåìûå ôàéëû íå äîëæíû áûòü ñæàòûìè èëè ðàçðåæåííûìè ôàéëàìè |
(àêòóàëüíî äëÿ NTFS, äëÿ FAT âûïîëíåíî àâòîìàòè÷åñêè). |
Требования для работы: |
1) Все используемые файлы должны быть читабельны. |
2) Минимальный процессор - 80386. |
3) В системе должно быть как минимум 592K свободной базовой памяти. |
4) Пути к используемым файлам не должны содержать символических ссылок NTFS |
(жёсткие ссылки допускаются). |
5) Используемые файлы не должны быть сжатыми или разреженными файлами |
(актуально для NTFS, для FAT выполнено автоматически). |
===================================================================== |
Äîêóìåíòàöèÿ â òåìó (ññûëêè ïðîâåðÿëèñü íà âàëèäíîñòü 08.08.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 |
ñïåöèôèêàöèÿ NTFS: file://C:/windows/system32/drivers/ntfs.sys |
è file://C:/ntldr ëèáî file://C:/bootmgr |
íåîôèöèàëüíîå îïèñàíèå NTFS: http://sourceforge.net/project/showfiles.php?group_id=13956&package_id=16543 |
îôèöèàëüíàÿ ñïåöèôèêàöèÿ ðàñøèðåíèÿ 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 |
îôèöèàëüíîå îïèñàíèå bcdedit äëÿ Vista: http://www.microsoft.com/whdc/system/platform/firmware/bcdedit_reff.mspx |
îôèöèàëüíîå îïèñàíèå ðàáîòû ñ áàçîé äàííûõ çàãðóç÷èêà Vista: http://www.microsoft.com/whdc/system/platform/firmware/bcd.mspx |
ôîðìàò òàáëèöû ðàçäåëîâ æ¸ñòêîãî äèñêà: http://www.microsoft.com/technet/prodtechnol/windows2000serv/reskit/prork/prcb_dis_qxql.mspx |
Документация в тему (ссылки проверялись на валидность 08.08.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 |
спецификация NTFS: file://C:/windows/system32/drivers/ntfs.sys |
и file://C:/ntldr либо file://C:/bootmgr |
неофициальное описание NTFS: http://sourceforge.net/project/showfiles.php?group_id=13956&package_id=16543 |
официальная спецификация расширения 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 |
официальное описание bcdedit для Vista: http://www.microsoft.com/whdc/system/platform/firmware/bcdedit_reff.mspx |
официальное описание работы с базой данных загрузчика Vista: http://www.microsoft.com/whdc/system/platform/firmware/bcd.mspx |
формат таблицы разделов жёсткого диска: http://www.microsoft.com/technet/prodtechnol/windows2000serv/reskit/prork/prcb_dis_qxql.mspx |
===================================================================== |
Ñõåìà èñïîëüçóåìîé ïàìÿòè: |
600-2000 êîä çàãðóç÷èêà (è äàííûå) |
2000-3000 ñòåê |
3000-3200 ñåêòîð MBR |
3200-3400 áóòñåêòîð ëîãè÷åñêîãî äèñêà |
3400-3C00 èíôîðìàöèÿ î êýøå äëÿ òàáëèö FAT16/FAT32: |
äëÿ FAT16 - ìàññèâ íà 0x100 áàéò, êàæäûé áàéò ðàâåí |
0 èëè 1 â çàâèñèìîñòè îò òîãî, çàãðóæåí ëè |
ñîîòâåòñòâóþùèé ñåêòîð òàáëèöû FAT16; |
äëÿ FAT32 - 100h âõîäîâ ïî 8 áàéò: 4 áàéòà |
(äâå ññûëêè - âïåð¸ä è íàçàä) äëÿ îðãàíèçàöèè L2-ñïèñêà |
âñåõ ïðî÷èòàííûõ ñåêòîðîâ â ïîðÿäêå âîçðàñòàíèÿ |
ïîñëåäíåãî âðåìåíè èñïîëüçîâàíèÿ + 4 áàéòà äëÿ íîìåðà |
ñåêòîðà; ïðè ïåðåïîëíåíèè êýøà âûêèäûâàåòñÿ ýëåìåíò èç |
ãîëîâû ñïèñêà, òî åñòü òîò, ê êîòîðîìó äîëüøå âñåõ |
íå áûëî îáðàùåíèé |
3400-3440 èíôîðìàöèÿ î êýøå äëÿ ôàéëîâûõ çàïèñåé NTFS â |
òàêîì æå ôîðìàòå, êàê è êýø äëÿ FAT32, íî íà 8 âõîäîâ |
3480-34C0 çàãîëîâêè äëÿ êýøåé çàïèñåé èíäåêñà NTFS |
3500-3D00 èíôîðìàöèÿ î êýøàõ çàïèñåé èíäåêñà NTFS: ñ êàæäîé |
ôàéëîâîé çàïèñüþ ñâÿçàí ñâîé êýø äëÿ |
ñîîòâåòñòâóþùåãî èíäåêñà |
4000-8000 ìåñòî äëÿ èíôîðìàöèè îá àòðèáóòàõ äëÿ NTFS |
60000-80000 òàáëèöà FAT12 / ìåñòî ïîä òàáëèöó FAT16 / |
êýø äëÿ òàáëèöû FAT32 / êýø äëÿ ñòðóêòóð NTFS |
80000-90000 òåêóùèé ðàññìàòðèâàåìûé êëàñòåð |
90000-92000 FAT: êýø äëÿ êîðíåâîé ïàïêè |
92000-... FAT: êýø äëÿ íåêîðíåâûõ ïàïîê (êàæäîé ïàïêå îòâîäèòñÿ |
2000h áàéò = 100h âõîäîâ, îäíîâðåìåííî â êýøå |
ìîæåò íàõîäèòüñÿ íå áîëåå 7 ïàïîê; |
òî÷íûé ðàçìåð îïðåäåëÿåòñÿ ðàçìåðîì äîñòóïíîé |
ôèçè÷åñêîé ïàìÿòè - êàê ïðàâèëî, íåïîñðåäñòâåííî |
ïåðåä A0000 ðàçìåùàåòñÿ EBDA, Extended BIOS Data Area) |
Схема используемой памяти: |
600-2000 код загрузчика (и данные) |
2000-3000 стек |
3000-3200 сектор MBR |
3200-3400 бутсектор логического диска |
3400-3C00 информация о кэше для таблиц FAT16/FAT32: |
для FAT16 - массив на 0x100 байт, каждый байт равен |
0 или 1 в зависимости от того, загружен ли |
соответствующий сектор таблицы FAT16; |
для FAT32 - 100h входов по 8 байт: 4 байта |
(две ссылки - вперёд и назад) для организации L2-списка |
всех прочитанных секторов в порядке возрастания |
последнего времени использования + 4 байта для номера |
сектора; при переполнении кэша выкидывается элемент из |
головы списка, то есть тот, к которому дольше всех |
не было обращений |
3400-3440 информация о кэше для файловых записей NTFS в |
таком же формате, как и кэш для FAT32, но на 8 входов |
3480-34C0 заголовки для кэшей записей индекса NTFS |
3500-3D00 информация о кэшах записей индекса NTFS: с каждой |
файловой записью связан свой кэш для |
соответствующего индекса |
4000-8000 место для информации об атрибутах для NTFS |
60000-80000 таблица FAT12 / место под таблицу FAT16 / |
кэш для таблицы FAT32 / кэш для структур NTFS |
80000-90000 текущий рассматриваемый кластер |
90000-92000 FAT: кэш для корневой папки |
92000-... FAT: кэш для некорневых папок (каждой папке отводится |
2000h байт = 100h входов, одновременно в кэше |
может находиться не более 7 папок; |
точный размер определяется размером доступной |
физической памяти - как правило, непосредственно |
перед A0000 размещается EBDA, Extended BIOS Data Area) |
===================================================================== |
Îñíîâíîé ïðîöåññ çàãðóçêè. |
0a. Çàãðóçêà èç-ïîä DOS è Win9x: óñòàíîâêà kordldr.win îñóùåñòâëÿåòñÿ |
ðàçìåùåíèåì êîìàíäû install=c:\kordldr.win â ïåðâîé ñòðîêå config.sys; |
ïðè ýòîì îñíîâíîé çàãðóç÷èê ñèñòåìû çàãðóæàåò kordldr.win êàê îáû÷íûé |
com-ôàéë, â êàêîé-òî ñåãìåíò ïî ñìåùåíèþ 100h è ïåðåäà¸ò óïðàâëåíèå |
â íà÷àëî êîäà (xxxx:0100). |
0á. Çàãðóçêà èç-ïîä WinNT/2000/XP: óñòàíîâêà kordldr.win îñóùåñòâëÿåòñÿ |
äîáàâëåíèåì ñòðîêè íàïîäîáèå c:\kordldr.win="KordOS" â ñåêöèþ |
[operating systems] ôàéëà boot.ini; åñëè çàãðóæàåìûé ôàéë èìååò ðàçìåð |
íå ìåíåå 8 Êá (0x2000 áàéò) è ïî ñìåùåíèþ 3 ñîäåðæèò ñèãíàòóðó 'NTFS' |
(â ñëó÷àå kordldr.win òàê è åñòü), òî îñíîâíîé çàãðóç÷èê êàæäîé èç |
ýòèõ ñèñòåì çàãðóæàåò kordldr.win ïî àäðåñó 0D00:0000 è ïåðåäà¸ò |
óïðàâëåíèå íà àäðåñ 0D00:0256. |
0â. Çàãðóçêà èç-ïîä Vista: óñòàíîâêà kordldr.win îñóùåñòâëÿåòñÿ ìàíèïóëÿöèÿìè |
ñ áàçîé äàííûõ îñíîâíîãî çàãðóç÷èêà ÷åðåç bcdedit è ïîäðîáíî îïèñàíà â |
èíñòðóêöèè ê kordldr.win; îñíîâíîé çàãðóç÷èê çàãðóæàåò öåëèêîì |
kordldr.win ïî àäðåñó 0000:7C00 è ïåðåäà¸ò óïðàâëåíèå â íà÷àëî êîäà. |
1. Ïðè çàãðóçêå èç-ïîä DOS/9x îñíîâíîé çàãðóç÷èê íå îæèäàåò, ÷òî çàãðóæåííàÿ |
èì ïðîãðàììà îêàæåòñÿ â ñâîþ î÷åðåäü çàãðóç÷èêîì, è â ýòîì ñëó÷àå |
kordldr.win îêàçûâàåòñÿ â óñëîâèÿõ, êîãäà îñíîâíîé çàãðóç÷èê óæå |
óñòàíîâèë êàêîå-òî îêðóæåíèå, â ÷àñòíîñòè, ïåðåõâàòèë íåêîòîðûå |
ïðåðûâàíèÿ. Ïîýòîìó ïåðåä îñòàëüíûìè äåéñòâèÿìè çàãðóç÷èê äîëæåí |
âîññòàíîâèòü ñèñòåìó â íà÷àëüíîå ñîñòîÿíèå. (Ïðè çàãðóçêå ïîä |
NT-ëèíåéêîé òàêîé ïðîáëåìû íå âîçíèêàåò, ïîñêîëüêó òàì îñíîâíîé |
çàãðóç÷èê íè÷åãî â ñèñòåìå íå òðîãàåò.) Ïîýòîìó ïåðåä ñîáñòâåííî |
èíèöèàëèçàöèåé KordOS ïðè ðàáîòå èç-ïîä DOS/9x ïðîèçâîäÿòñÿ |
äîïîëíèòåëüíûå äåéñòâèÿ. Ïåðâûì äåëîì kordldr ïðîâåðÿåò, êàêîé èç |
ñëó÷àåâ 0à è 0â èìååò ìåñòî (ñëó÷àé 0á îòëè÷àåòñÿ òåì, ÷òî ïåðåäà¸ò |
óïðàâëåíèå íå íà íà÷àëî êîäà): îïðåäåëÿåò çíà÷åíèå ip (êîìàíäà call |
ïîìåùàåò â ñòåê àäðåñ ñëåäóþùåé ïîñëå call èíñòðóêöèè, êîìàíäà pop si |
âûòàëêèâàåò åãî â ðåãèñòð si), è åñëè îíî ðàâíî 100h, òî kordldr |
çàãðóæåí êàê com-ôàéë èç-ïîä DOS/9x. Òîãäà îí ñïðàøèâàåò ïîäòâåðæäåíèÿ |
ó ïîëüçîâàòåëÿ (ïîñêîëüêó â ýòîé ñõåìå kordldr çàãðóæàåòñÿ âñåãäà, |
îí äîëæåí îñòàâèòü âîçìîæíîñòü ïðîäîëæèòü çàãðóçêó DOS/9x). Åñëè |
ïîëüçîâàòåëü õî÷åò ïðîäîëæèòü îáû÷íóþ çàãðóçêó, kordldr çàâåðøàåòñÿ. |
Èíà÷å èñïîëüçóåòñÿ òîò ôàêò, ÷òî ïðè âûäà÷å ïðåðûâàíèÿ ïåðåçàãðóçêè |
int 19h ñèñòåìà ïðåäâàðèòåëüíî ñíèìàåò âñå ñâîè ïåðåõâàòû BIOSîâñêèõ |
ïðåðûâàíèé, à ïîòîì â ñâîþ î÷åðåäü âûäà¸ò int 19h óæå BIOSó. Òàê ÷òî |
kordldr óñòàíàâëèâàåò ñâîé îáðàáîò÷èê òðàññèðîâî÷íîãî ïðåðûâàíèÿ, |
óñòàíàâëèâàåò ôëàã òðàññèðîâêè è ïåðåäà¸ò óïðàâëåíèå DOSîâñêîìó |
îáðàáîò÷èêó. Îáðàáîò÷èê òðàññèðîâî÷íîãî ïðåðûâàíèÿ íè÷åãî íå äåëàåò |
äî òåõ ïîð, ïîêà ñëåäóþùåé èíñòðóêöèåé íå îêàçûâàåòñÿ int 19h, à |
â ýòîò ìîìåíò îòáèðàåò óïðàâëåíèå è ïðîäîëæàåò çàãðóçêó KordOS. |
Ïðè ýòîì BIOSîâñêèå îáðàáîò÷èêè âîññòàíîâëåíû çà èñêëþ÷åíèåì, |
áûòü ìîæåò, ïðåðûâàíèÿ òàéìåðà int 8, êîòîðîå, âîçìîæíî, âîññòàíîâëåíî |
äî êîìàíäû jmp far íà îðèãèíàëüíûé îáðàáîò÷èê.  ïîñëåäíåì ñëó÷àå åãî |
íóæíî âîññòàíîâèòü ÿâíî. |
2. Çàãðóç÷èê ïåðåìåùàåò ñâîé êîä íà àäðåñ 0000:0600. |
3. (ìåòêà real_entry) Çàãðóç÷èê óñòàíàâëèâàåò ñåãìåíòíûå ðåãèñòðû ds = es = 0, |
íàñòðàèâàåò ñòåê ss:sp = 0000:3000 è óñòàíàâëèâàåò bp òàê, ÷òîáû |
âñå äàííûå ìîæíî áûëî àäðåñîâàòü ÷åðåç [bp+N] ñ îäíîáàéòîâûì N |
(â äàëüíåéøåì îíè òàê è áóäóò àäðåñîâàòüñÿ äëÿ îñâîáîæäåíèÿ ds è |
ýêîíîìèè íà ðàçìåðå êîäà). Ðàçðåøàåò ïðåðûâàíèÿ íà ñëó÷àé, åñëè |
îíè áûëè çàïðåùåíû. Âûäà¸ò ñîîáùåíèå î íà÷àëå çàãðóçêè, íà÷èíàþùååñÿ |
ñ âåñ¸ëîé ðîæèöû (ñèìâîë ñ ASCII-êîäîì 2). |
4. Îïðåäåëÿåò õàðàêòåðèñòèêè æ¸ñòêîãî äèñêà, óêàçàííîãî â êà÷åñòâå |
çàãðóçî÷íîãî: ïðîâåðÿåò ïîääåðæêó LBA (ôóíêöèÿ 41h ïðåðûâàíèÿ 13h), |
åñëè LBA íå ïîääåðæèâàåòñÿ, òî îïðåäåëÿåò ãåîìåòðèþ - ÷èñëî äîðîæåê |
è ÷èñëî ñåêòîðîâ íà äîðîæêå (ôóíêöèÿ 8 ïðåðûâàíèÿ 13h), ýòè ïàðàìåòðû |
íóæíû ôóíêöèè ÷òåíèÿ ñ äèñêà. |
5. (ìåòêà new_partition_ex) Óñòðàèâàåò öèêë ïî ðàçäåëàì æ¸ñòêîãî äèñêà. |
Öåëü öèêëà - äëÿ êàæäîãî ëîãè÷åñêîãî äèñêà ïîïûòàòüñÿ çàãðóçèòüñÿ ñ |
íåãî (äåéñòâèÿ ïî çàãðóçêå ñ êîíêðåòíîãî ëîãè÷åñêîãî äèñêà íà÷èíàþòñÿ |
ñ ìåòêè not_extended), ïðè îøèáêå çàãðóçêè óïðàâëåíèå ïåðåäà¸òñÿ |
íàçàä ýòîìó öèêëó (ìåòêà next_partition), è ïîèñê ïîäõîäÿùåãî ðàçäåëà |
ïðîäîëæàåòñÿ. Íà âûõîäå çàïîëíÿåòñÿ îäíà ïåðåìåííàÿ partition_start, |
èìåþùàÿ ñìûñë íà÷àëà òåêóùåãî ðàññìàòðèâàåìîãî ëîãè÷åñêîãî äèñêà, |
íî ïî õîäó äåëà èç-çà ïðèêîëîâ òàáëèö ðàçäåëîâ èñïîëüçóþòñÿ åù¸ ÷åòûðå |
ïåðåìåííûõ. cur_partition_ofs - ôàêòè÷åñêè ñ÷¸ò÷èê öèêëà, ôîðìàëüíî |
óêàçàòåëü íà òåêóùèé âõîä â òåêóùåé çàãðóçî÷íîé çàïèñè. Ñàìà |
çàãðóçî÷íàÿ çàïèñü ñ÷èòûâàåòñÿ â ïàìÿòü íà÷èíàÿ ñ àäðåñà 3000h. |
Òðè îñòàâøèõñÿ íóæíû äëÿ ïðàâèëüíîé ðàáîòû ñ ðàñøèðåííûìè ðàçäåëàìè. |
 êàæäîé çàãðóçî÷íîé çàïèñè ïîìåùàåòñÿ íå áîëåå 4 çàïèñåé î ðàçäåëàõ. |
Ïîýòîìó ãëàâíîé çàãðóçî÷íîé çàïèñè, ðàçìåùàþùåéñÿ â ïåðâîì ôèçè÷åñêîì |
ñåêòîðå äèñêà, ìîæåò íå õâàòèòü, è îáû÷íî ñîçäà¸òñÿ òàê íàçûâàåìûé |
ðàñøèðåííûé ðàçäåë ñ ðàñøèðåííûìè çàãðóçî÷íûìè çàïèñÿìè, ôîðìàò |
êîòîðûõ ïî÷òè èäåíòè÷åí ãëàâíîé. Ðàñøèðåííûé ðàçäåë ìîæåò áûòü òîëüêî |
îäèí, íî â í¸ì ìîæåò áûòü ìíîãî ëîãè÷åñêèõ äèñêîâ è ðàñøèðåííûõ |
çàãðóçî÷íûõ çàïèñåé. Ðàñøèðåííûå çàãðóçî÷íûå çàïèñè îðãàíèçîâàíû |
â îäíîñâÿçíûé ñïèñîê, â êàæäîé òàêîé çàïèñè ïåðâûé âõîä óêàçûâàåò |
íà ñîîòâåòñòâóþùèé ëîãè÷åñêèé äèñê, à âòîðîé - íà ñëåäóþùóþ ðàñøèðåííóþ |
çàãðóçî÷íóþ çàïèñü. |
Ïðè ýòîì â ãëàâíîé çàãðóçî÷íîé çàïèñè âñå àäðåñà ðàçäåëîâ ÿâëÿþòñÿ |
àáñîëþòíûìè íîìåðàìè ñåêòîðîâ. Â ðàñøèðåííûõ æå çàïèñÿõ àäðåñà ðàçäåëîâ |
îòíîñèòåëüíû, ïðè÷¸ì ñ ðàçíûìè áàçàìè: àäðåñ ëîãè÷åñêîãî äèñêà |
óêàçûâàåòñÿ îòíîñèòåëüíî ðàñøèðåííîé çàïèñè, à àäðåñ ñëåäóþùåé |
ðàñøèðåííîé çàïèñè óêàçûâàåòñÿ îòíîñèòåëüíî íà÷àëà ðàñøèðåííîãî |
ðàçäåëà. Òàêîé ðàçíîáîé âûãëÿäèò íåñêîëüêî ñòðàííî, íî èìååò ìåñòî |
áûòü. Òðè îñòàâøèõñÿ ïåðåìåííûõ ñîäåðæàò: extended_part_start - |
íà÷àëî ðàñøèðåííîãî ðàçäåëà; extended_parent - òåêóùàÿ ðàññìàòðèâàåìàÿ |
ðàñøèðåííàÿ çàãðóçî÷íàÿ çàïèñü; extended_part_cur - ñëåäóþùàÿ |
çàãðóçî÷íàÿ çàïèñü äëÿ ðàññìîòðåíèÿ. |
Öèêë âûãëÿäèò òàê: ïðîñìàòðèâàþòñÿ âñå ðàçäåëû, óêàçàííûå â òåêóùåé |
(ãëàâíîé èëè ðàñøèðåííîé) çàãðóçî÷íîé çàïèñè; äëÿ íîðìàëüíûõ ðàçäåëîâ |
(îíè æå ëîãè÷åñêèå äèñêè) ïðîèñõîäèò ïåðåõîä íà not_extended, ãäå |
óñòàíàâëèâàåòñÿ partition_start è íà÷èíàåòñÿ ñîáñòâåííî çàãðóçêà |
(ïîñëåäóþùèå øàãè); ïðè âñòðå÷å ñ ðàçäåëîì, òèï êîòîðîãî óêàçûâàåò |
íà ðàñøèðåííîñòü (5 èëè 0xF), êîä çàïîìèíàåò íà÷àëî ýòîãî ðàçäåëà |
(â ãëàâíîé çàãðóçî÷íîé çàïèñè òàêîé òèï îçíà÷àåò ðàñøèðåííûé ðàçäåë, |
â ðàñøèðåííîé - òîëüêî óêàçàòåëü íà ñëåäóþùóþ ðàñøèðåííóþ çàïèñü, |
â îáîèõ ñëó÷àÿõ îí ìîæåò âñòðåòèòüñÿ òîëüêî îäèí ðàç â äàííîé çàïèñè); |
êîãäà êîä äîõîäèò äî êîíöà ñïèñêà, âñå íîðìàëüíûå ðàçäåëû, îïèñûâàåìûå |
â ýòîé çàïèñè, óæå ïðîñìîòðåíû, òàê ÷òî êîä ñ ÷èñòîé ñîâåñòüþ ïåðåõîäèò |
ê ñëåäóþùåé ðàñøèðåííîé çàïèñè. Åñëè îí å¸ íå âñòðåòèë, çíà÷èò, óæå |
âñå ëîãè÷åñêèå ðàçäåëû áûëè ïîäâåðãíóòû ïîïûòêàì çàãðóçèòüñÿ, è âñå |
áåçðåçóëüòàòíî, òàê ÷òî âûâîäèòñÿ ðóãàòåëüñòâî è ðàáîòà îñòàíàâëèâàåòñÿ |
Основной процесс загрузки. |
0a. Загрузка из-под DOS и Win9x: установка kordldr.win осуществляется |
размещением команды install=c:\kordldr.win в первой строке config.sys; |
при этом основной загрузчик системы загружает kordldr.win как обычный |
com-файл, в какой-то сегмент по смещению 100h и передаёт управление |
в начало кода (xxxx:0100). |
0б. Загрузка из-под WinNT/2000/XP: установка kordldr.win осуществляется |
добавлением строки наподобие c:\kordldr.win="KordOS" в секцию |
[operating systems] файла boot.ini; если загружаемый файл имеет размер |
не менее 8 Кб (0x2000 байт) и по смещению 3 содержит сигнатуру 'NTFS' |
(в случае kordldr.win так и есть), то основной загрузчик каждой из |
этих систем загружает kordldr.win по адресу 0D00:0000 и передаёт |
управление на адрес 0D00:0256. |
0в. Загрузка из-под Vista: установка kordldr.win осуществляется манипуляциями |
с базой данных основного загрузчика через bcdedit и подробно описана в |
инструкции к kordldr.win; основной загрузчик загружает целиком |
kordldr.win по адресу 0000:7C00 и передаёт управление в начало кода. |
1. При загрузке из-под DOS/9x основной загрузчик не ожидает, что загруженная |
им программа окажется в свою очередь загрузчиком, и в этом случае |
kordldr.win оказывается в условиях, когда основной загрузчик уже |
установил какое-то окружение, в частности, перехватил некоторые |
прерывания. Поэтому перед остальными действиями загрузчик должен |
восстановить систему в начальное состояние. (При загрузке под |
NT-линейкой такой проблемы не возникает, поскольку там основной |
загрузчик ничего в системе не трогает.) Поэтому перед собственно |
инициализацией KordOS при работе из-под DOS/9x производятся |
дополнительные действия. Первым делом kordldr проверяет, какой из |
случаев 0а и 0в имеет место (случай 0б отличается тем, что передаёт |
управление не на начало кода): определяет значение ip (команда call |
помещает в стек адрес следующей после call инструкции, команда pop si |
выталкивает его в регистр si), и если оно равно 100h, то kordldr |
загружен как com-файл из-под DOS/9x. Тогда он спрашивает подтверждения |
у пользователя (поскольку в этой схеме kordldr загружается всегда, |
он должен оставить возможность продолжить загрузку DOS/9x). Если |
пользователь хочет продолжить обычную загрузку, kordldr завершается. |
Иначе используется тот факт, что при выдаче прерывания перезагрузки |
int 19h система предварительно снимает все свои перехваты BIOSовских |
прерываний, а потом в свою очередь выдаёт int 19h уже BIOSу. Так что |
kordldr устанавливает свой обработчик трассировочного прерывания, |
устанавливает флаг трассировки и передаёт управление DOSовскому |
обработчику. Обработчик трассировочного прерывания ничего не делает |
до тех пор, пока следующей инструкцией не оказывается int 19h, а |
в этот момент отбирает управление и продолжает загрузку KordOS. |
При этом BIOSовские обработчики восстановлены за исключением, |
быть может, прерывания таймера int 8, которое, возможно, восстановлено |
до команды jmp far на оригинальный обработчик. В последнем случае его |
нужно восстановить явно. |
2. Загрузчик перемещает свой код на адрес 0000:0600. |
3. (метка real_entry) Загрузчик устанавливает сегментные регистры ds = es = 0, |
настраивает стек ss:sp = 0000:3000 и устанавливает bp так, чтобы |
все данные можно было адресовать через [bp+N] с однобайтовым N |
(в дальнейшем они так и будут адресоваться для освобождения ds и |
экономии на размере кода). Разрешает прерывания на случай, если |
они были запрещены. Выдаёт сообщение о начале загрузки, начинающееся |
с весёлой рожицы (символ с ASCII-кодом 2). |
4. Определяет характеристики жёсткого диска, указанного в качестве |
загрузочного: проверяет поддержку LBA (функция 41h прерывания 13h), |
если LBA не поддерживается, то определяет геометрию - число дорожек |
и число секторов на дорожке (функция 8 прерывания 13h), эти параметры |
нужны функции чтения с диска. |
5. (метка new_partition_ex) Устраивает цикл по разделам жёсткого диска. |
Цель цикла - для каждого логического диска попытаться загрузиться с |
него (действия по загрузке с конкретного логического диска начинаются |
с метки not_extended), при ошибке загрузки управление передаётся |
назад этому циклу (метка next_partition), и поиск подходящего раздела |
продолжается. На выходе заполняется одна переменная partition_start, |
имеющая смысл начала текущего рассматриваемого логического диска, |
но по ходу дела из-за приколов таблиц разделов используются ещё четыре |
переменных. cur_partition_ofs - фактически счётчик цикла, формально |
указатель на текущий вход в текущей загрузочной записи. Сама |
загрузочная запись считывается в память начиная с адреса 3000h. |
Три оставшихся нужны для правильной работы с расширенными разделами. |
В каждой загрузочной записи помещается не более 4 записей о разделах. |
Поэтому главной загрузочной записи, размещающейся в первом физическом |
секторе диска, может не хватить, и обычно создаётся так называемый |
расширенный раздел с расширенными загрузочными записями, формат |
которых почти идентичен главной. Расширенный раздел может быть только |
один, но в нём может быть много логических дисков и расширенных |
загрузочных записей. Расширенные загрузочные записи организованы |
в односвязный список, в каждой такой записи первый вход указывает |
на соответствующий логический диск, а второй - на следующую расширенную |
загрузочную запись. |
При этом в главной загрузочной записи все адреса разделов являются |
абсолютными номерами секторов. В расширенных же записях адреса разделов |
относительны, причём с разными базами: адрес логического диска |
указывается относительно расширенной записи, а адрес следующей |
расширенной записи указывается относительно начала расширенного |
раздела. Такой разнобой выглядит несколько странно, но имеет место |
быть. Три оставшихся переменных содержат: extended_part_start - |
начало расширенного раздела; extended_parent - текущая рассматриваемая |
расширенная загрузочная запись; extended_part_cur - следующая |
загрузочная запись для рассмотрения. |
Цикл выглядит так: просматриваются все разделы, указанные в текущей |
(главной или расширенной) загрузочной записи; для нормальных разделов |
(они же логические диски) происходит переход на not_extended, где |
устанавливается partition_start и начинается собственно загрузка |
(последующие шаги); при встрече с разделом, тип которого указывает |
на расширенность (5 или 0xF), код запоминает начало этого раздела |
(в главной загрузочной записи такой тип означает расширенный раздел, |
в расширенной - только указатель на следующую расширенную запись, |
в обоих случаях он может встретиться только один раз в данной записи); |
когда код доходит до конца списка, все нормальные разделы, описываемые |
в этой записи, уже просмотрены, так что код с чистой совестью переходит |
к следующей расширенной записи. Если он её не встретил, значит, уже |
все логические разделы были подвергнуты попыткам загрузиться, и все |
безрезультатно, так что выводится ругательство и работа останавливается |
(jmp $). |
Ìîæåò âîçíèêíóòü âîïðîñ, çà÷åì íóæíà òàêàÿ ñëîæíàÿ ñõåìà è ïî÷åìó |
íåëüçÿ óçíàòü íóæíûé ëîãè÷åñêèé äèñê çàðàíåå èëè õîòÿ áû îãðàíè÷èòüñÿ |
ïåðâûì ïîïàâøèìñÿ ëîãè÷åñêèì äèñêîì, íå êðóòÿ öèêë. Òàê âîò, âàðèàíò |
ñ ïðåäâàðèòåëüíûì îïðåäåëåíèåì íóæíîãî ðàçäåëà â äàííîì ñëó÷àå íå |
èñïîëüçóåòñÿ, ïîñêîëüêó ïîâë¸ê áû çà ñîáîé íåòðèâèàëüíûå ëèøíèå |
äåéñòâèÿ ïî óñòàíîâêå (â òåêóùåì âèäå óñòàíîâêó ìîæíî ïðîâåñòè âðó÷íóþ, |
è îíà ñâîäèòñÿ ê óêàçàíèþ ñèñòåìíîìó çàãðóç÷èêó íà ñóùåñòâîâàíèå |
kordldr); êñòàòè, â àëüòåðíàòèâíîé âåðñèè çàãðóçêè ïîñëå |
Windows-çàãðóç÷èêà, êîãäà óñòàíîâêà îñóùåñòâëÿåòñÿ íå âðó÷íóþ, à |
ñïåöèàëüíîé ïðîãðàììîé ïîä Windows, èñïîëüçóåòñÿ ìîäèôèöèðîâàííàÿ |
âåðñèÿ, â êîòîðîé êàê ðàç íà÷àëüíûé ôèçè÷åñêèé ñåêòîð íóæíîãî ðàçäåëà |
ïðîïèñûâàåòñÿ óñòàíîâùèêîì. Ñàì kordldr íå ìîæåò óñòàíîâèòü, ñ êàêîãî |
ðàçäåëà åãî çàãðóçèë Windows-çàãðóç÷èê (è âîîáùå ïîä NT/2000/XP îáÿçàí |
áûòü ôàéëîì íà äèñêå C:\). Âàðèàíò ñ ïåðâûì ïîïàâøèìñÿ ëîãè÷åñêèì |
äèñêîì áûë ðåàëèçîâàí â ïåðâîé âåðñèè çàãðóç÷èêà, íî ïî õîäó äåëà |
îáíàðóæèëîñü, ÷òî òàêè íóæíî êðóòèòü öèêë: âî-âòîðûõ, ìîæåò áûòü |
ïðèÿòíûì, ÷òî ñàìà ñèñòåìà ìîæåò ñòîÿòü âîâñå íå íà ñèñòåìíîì C:\, à è |
íà äðóãèõ äèñêàõ; âî-ïåðâûõ, äèñê C: ìîæåò è íå áûòü ïåðâûì ëîãè÷åñêèì |
ðàçäåëîì - Vista ëþáèò ñîçäàâàòü ñêðûòûé ïåðâè÷íûé ðàçäåë ïåðåä |
ñèñòåìíûì, è òîãäà äèñê C: ñòàíîâèòñÿ âòîðûì ëîãè÷åñêèì. |
6. Èçâåùàåò ïîëüçîâàòåëÿ î òîì, ÷òî ïðîèñõîäèò ïîïûòêà çàãðóçêè ñ î÷åðåäíîãî |
ëîãè÷åñêîãî äèñêà. |
7. ×èòàåò ïåðâûé ñåêòîð ëîãè÷åñêîãî äèñêà è îïðåäåëÿåò ôàéëîâóþ ñèñòåìó. |
È â FAT, è â NTFS ïîëå ñî ñìåùåíèåì +11 ñîäåðæèò ÷èñëî áàéò â ñåêòîðå |
è äîëæíî ñîâïàäàòü ñ õàðàêòåðèñòèêîé ôèçè÷åñêîãî íîñèòåëÿ, òî åñòü |
200h áàéò. È â FAT, è â NTFS ïîëå ñî ñìåùåíèåì +13 ñîäåðæèò ÷èñëî |
ñåêòîðîâ â êëàñòåðå è äîëæíî áûòü ñòåïåíüþ äâîéêè. |
Êðèòåðèé NTFS: ïîëå ñî ñìåùåíèåì +3 ñîäåðæèò ñòðîêó NTFS è ïîëå ñî |
ñìåùåíèåì +16 íóëåâîå (â FAT îíî ñîäåðæèò ÷èñëî òàáëèö FAT è îáÿçàíî |
áûòü íåíóëåâûì). |
Êðèòåðèé FAT: çàãðóç÷èê âû÷èñëÿåò ÷èñëî êëàñòåðîâ, îïðåäåëÿåò |
ïðåäïîëîæèòåëüíûé òèï (FAT12/FAT16/FAT32) è ïðîâåðÿåò áàéò ïî ñìåùåíèþ |
+38 äëÿ FAT12/16, +66 äëÿ FAT32 (îí äîëæåí áûòü ðàâåí 0x29). |
Ïîñëå îïðåäåëåíèÿ òèïà ôàéëîâîé ñèñòåìû èçâåùàåò ïîëüçîâàòåëÿ îá |
îïðåäåë¸ííîì òèïå. Åñëè ôàéëîâàÿ ñèñòåìà íå ðàñïîçíàíà, âûäà¸ò |
ñîîòâåòñòâóþùåå ñîîáùåíèå è ïåðåõîäèò ê ñëåäóþùåìó ëîãè÷åñêîìó äèñêó. |
8a. Äëÿ FAT12-òîìîâ: çàñîâûâàåò â ñòåê èäåíòèôèêàòîð ôàéëîâîé ñèñòåìû - |
êîíñòàíòó '12'; óñòàíàâëèâàåò óêàçàòåëü íà ôóíêöèþ ïîëó÷åíèÿ ñëåäóþùåãî |
â öåïî÷êå FAT êëàñòåðà íà FAT12-îáðàáîò÷èê; ñ÷èòûâàåò â ïàìÿòü âñþ |
òàáëèöó FAT12 (îíà íå ïðåâîñõîäèò 0x1800 áàéò = 6 Êá), ïðè îøèáêå |
÷òåíèÿ ïûòàåòñÿ èñïîëüçîâàòü äðóãèå êîïèè FAT. |
8á. Äëÿ FAT16-òîìîâ: çàñîâûâàåò â ñòåê èäåíòèôèêàòîð ôàéëîâîé ñèñòåìû - |
êîíñòàíòó '16'; óñòàíàâëèâàåò óêàçàòåëü íà ôóíêöèþ ïîëó÷åíèÿ ñëåäóþùåãî |
â öåïî÷êå FAT êëàñòåðà íà FAT16-îáðàáîò÷èê; èíèöèàëèçèðóåò èíôîðìàöèþ |
î êýøå ñåêòîðîâ FAT (ìàññèâ áàéò ñ âîçìîæíûìè çíà÷åíèÿìè 0 è 1, |
îçíà÷àþùèìè, áûë ëè óæå çàãðóæåí ñîîòâåòñòâóþùèé ñåêòîð - âñåãî â |
òàáëèöå FAT16 íå áîëåå 0x100 ñåêòîðîâ) - íè îäèí ñåêòîð åù¸ íå |
çàãðóæåí, âñå áàéòû íóëåâûå. |
8â. Äëÿ FAT32-òîìîâ: çàñîâûâàåò â ñòåê èäåíòèôèêàòîð ôàéëîâîé ñèñòåìû - |
êîíñòàíòó '32'; óñòàíàâëèâàåò óêàçàòåëü íà ôóíêöèþ ïîëó÷åíèÿ ñëåäóþùåãî |
â öåïî÷êå FAT êëàñòåðà íà FAT16-îáðàáîò÷èê; èíèöèàëèçèðóåò èíôîðìàöèþ |
î êýøå ñåêòîðîâ FAT (ôîðìàò èíôîðìàöèè îïèñàí âûøå, â ðàñïðåäåëåíèè |
èñïîëüçóåìîé çàãðóç÷èêîì ïàìÿòè) - íè îäèí ñåêòîð åù¸ íå çàãðóæåí. |
8ã. Îáùåå äëÿ FAT-òîìîâ: îïðåäåëÿåò çíà÷åíèÿ ñëóæåáíûõ ïåðåìåííûõ |
root_start (ïåðâûé ñåêòîð êîðíåâîãî êàòàëîãà â FAT12/16, èãíîðèðóåòñÿ |
ïðè îáðàáîòêå FAT32-òîìîâ), data_start (íà÷àëî äàííûõ ñ ïîïðàâêîé, |
ââîäèìîé äëÿ òîãî, ÷òîáû êëàñòåð N íà÷èíàëñÿ ñ ñåêòîðà |
N*sectors_per_cluster+data_start), root_clus (ïåðâûé êëàñòåð êîðíåâîãî |
êàòàëîãà â FAT32, 0 â FAT12/16); óñòàíàâëèâàåò óêàçàòåëü íà ôóíêöèþ |
çàãðóçêè ôàéëà íà FAT-îáðàáîò÷èê. |
8ä. Äëÿ NTFS-òîìîâ: çàñîâûâàåò â ñòåê èäåíòèôèêàòîð ôàéëîâîé ñèñòåìû - |
êîíñòàíòó 'nt'; îïðåäåëÿåò çíà÷åíèå ñëóæåáíîé ïåðåìåííîé frs_size |
(ðàçìåð â áàéòàõ ôàéëîâîé çàïèñè, File Record Segment), äëÿ ïîëíîé |
êîððåêòíîñòè ïðîâåðÿåò, ÷òî ýòî çíà÷åíèå (ðàâíîå 0x400 áàéò íà âñåõ |
ðåàëüíûõ NTFS-òîìàõ - åäèíñòâåííûé ñïîñîá èçìåíèòü åãî çàêëþ÷àåòñÿ |
â ïåðåñîçäàíèè âñåõ ñèñòåìíûõ ñòðóêòóð âðó÷íóþ) íå ïðåâîñõîäèò 0x1000 |
è êðàòíî ðàçìåðó ñåêòîðà 0x200 áàéò; èíèöèàëèçèðóåò êýø ôàéëîâûõ |
çàïèñåé - íè÷åãî åù¸ íå çàãðóæåíî; ñ÷èòûâàåò ïåðâûé êëàñòåð $MFT |
è çàãðóæàåò èíôîðìàöèþ î ðàñïîëîæåíèè íà äèñêå âñåé òàáëèöû $MFT |
(àòðèáóò 0x80, $Data); óñòàíàâëèâàåò óêàçàòåëü íà ôóíêöèþ çàãðóçêè |
ôàéëà íà NTFS-îáðàáîò÷èê. |
9. (ìåòêà load_secondary) Âûçûâàåò ôóíêöèþ çàãðóçêè ôàéëà äëÿ ôàéëà âòîðè÷íîãî |
çàãðóç÷èêà. Ïðè îáíàðóæåíèè îøèáêè ïåðåõîäèò íà îáðàáîò÷èê îøèáîê ñ |
ñîîòâåòñòâóþùèì ñîîáùåíèåì. |
10. Óñòàíàâëèâàåò ðåãèñòðû äëÿ âòîðè÷íîãî çàãðóç÷èêà: al='h' (æ¸ñòêèé äèñê), |
ah=íîìåð äèñêà (äëÿ ãîòîâîãî áèíàðíèêà - 0 (BIOS-èäåíòèôèêàòîð 80h), |
ìîæåò áûòü èçìåí¸í ïóò¸ì ìîäèôèêàöèè êîíñòàíòû â èñõîäíèêå èëè |
ñïåöèàëüíûì óñòàíîâùèêîì), bx=èäåíòèôèêàòîð ôàéëîâîé ñèñòåìû (áåð¸òñÿ |
èç ñòåêà, êóäà ðàíåå áûë çàñóíóò íà øàãå 8), ds:si=óêàçàòåëü íà |
callback-ôóíêöèþ. |
11. Ïåðåäà¸ò óïðàâëåíèå âòîðè÷íîìó çàãðóç÷èêó äàëüíèì ïåðåõîäîì íà 1000:0000. |
Может возникнуть вопрос, зачем нужна такая сложная схема и почему |
нельзя узнать нужный логический диск заранее или хотя бы ограничиться |
первым попавшимся логическим диском, не крутя цикл. Так вот, вариант |
с предварительным определением нужного раздела в данном случае не |
используется, поскольку повлёк бы за собой нетривиальные лишние |
действия по установке (в текущем виде установку можно провести вручную, |
и она сводится к указанию системному загрузчику на существование |
kordldr); кстати, в альтернативной версии загрузки после |
Windows-загрузчика, когда установка осуществляется не вручную, а |
специальной программой под Windows, используется модифицированная |
версия, в которой как раз начальный физический сектор нужного раздела |
прописывается установщиком. Сам kordldr не может установить, с какого |
раздела его загрузил Windows-загрузчик (и вообще под NT/2000/XP обязан |
быть файлом на диске C:\). Вариант с первым попавшимся логическим |
диском был реализован в первой версии загрузчика, но по ходу дела |
обнаружилось, что таки нужно крутить цикл: во-вторых, может быть |
приятным, что сама система может стоять вовсе не на системном C:\, а и |
на других дисках; во-первых, диск C: может и не быть первым логическим |
разделом - Vista любит создавать скрытый первичный раздел перед |
системным, и тогда диск C: становится вторым логическим. |
6. Извещает пользователя о том, что происходит попытка загрузки с очередного |
логического диска. |
7. Читает первый сектор логического диска и определяет файловую систему. |
И в FAT, и в NTFS поле со смещением +11 содержит число байт в секторе |
и должно совпадать с характеристикой физического носителя, то есть |
200h байт. И в FAT, и в NTFS поле со смещением +13 содержит число |
секторов в кластере и должно быть степенью двойки. |
Критерий NTFS: поле со смещением +3 содержит строку NTFS и поле со |
смещением +16 нулевое (в FAT оно содержит число таблиц FAT и обязано |
быть ненулевым). |
Критерий FAT: загрузчик вычисляет число кластеров, определяет |
предположительный тип (FAT12/FAT16/FAT32) и проверяет байт по смещению |
+38 для FAT12/16, +66 для FAT32 (он должен быть равен 0x29). |
После определения типа файловой системы извещает пользователя об |
определённом типе. Если файловая система не распознана, выдаёт |
соответствующее сообщение и переходит к следующему логическому диску. |
8a. Для FAT12-томов: засовывает в стек идентификатор файловой системы - |
константу '12'; устанавливает указатель на функцию получения следующего |
в цепочке FAT кластера на FAT12-обработчик; считывает в память всю |
таблицу FAT12 (она не превосходит 0x1800 байт = 6 Кб), при ошибке |
чтения пытается использовать другие копии FAT. |
8б. Для FAT16-томов: засовывает в стек идентификатор файловой системы - |
константу '16'; устанавливает указатель на функцию получения следующего |
в цепочке FAT кластера на FAT16-обработчик; инициализирует информацию |
о кэше секторов FAT (массив байт с возможными значениями 0 и 1, |
означающими, был ли уже загружен соответствующий сектор - всего в |
таблице FAT16 не более 0x100 секторов) - ни один сектор ещё не |
загружен, все байты нулевые. |
8в. Для FAT32-томов: засовывает в стек идентификатор файловой системы - |
константу '32'; устанавливает указатель на функцию получения следующего |
в цепочке FAT кластера на FAT16-обработчик; инициализирует информацию |
о кэше секторов FAT (формат информации описан выше, в распределении |
используемой загрузчиком памяти) - ни один сектор ещё не загружен. |
8г. Общее для FAT-томов: определяет значения служебных переменных |
root_start (первый сектор корневого каталога в FAT12/16, игнорируется |
при обработке FAT32-томов), data_start (начало данных с поправкой, |
вводимой для того, чтобы кластер N начинался с сектора |
N*sectors_per_cluster+data_start), root_clus (первый кластер корневого |
каталога в FAT32, 0 в FAT12/16); устанавливает указатель на функцию |
загрузки файла на FAT-обработчик. |
8д. Для NTFS-томов: засовывает в стек идентификатор файловой системы - |
константу 'nt'; определяет значение служебной переменной frs_size |
(размер в байтах файловой записи, File Record Segment), для полной |
корректности проверяет, что это значение (равное 0x400 байт на всех |
реальных NTFS-томах - единственный способ изменить его заключается |
в пересоздании всех системных структур вручную) не превосходит 0x1000 |
и кратно размеру сектора 0x200 байт; инициализирует кэш файловых |
записей - ничего ещё не загружено; считывает первый кластер $MFT |
и загружает информацию о расположении на диске всей таблицы $MFT |
(атрибут 0x80, $Data); устанавливает указатель на функцию загрузки |
файла на NTFS-обработчик. |
9. (метка load_secondary) Вызывает функцию загрузки файла для файла вторичного |
загрузчика. При обнаружении ошибки переходит на обработчик ошибок с |
соответствующим сообщением. |
10. Устанавливает регистры для вторичного загрузчика: al='h' (жёсткий диск), |
ah=номер диска (для готового бинарника - 0 (BIOS-идентификатор 80h), |
может быть изменён путём модификации константы в исходнике или |
специальным установщиком), bx=идентификатор файловой системы (берётся |
из стека, куда ранее был засунут на шаге 8), ds:si=указатель на |
callback-функцию. |
11. Передаёт управление вторичному загрузчику дальним переходом на 1000:0000. |
Ôóíêöèÿ îáðàòíîãî âûçîâà äëÿ âòîðè÷íîãî çàãðóç÷èêà: |
ïðåäîñòàâëÿåò âîçìîæíîñòü ÷òåíèÿ ôàéëà. |
Âõîä è âûõîä îïèñàíû â ñïåöèôèêàöèè íà çàãðóç÷èê. |
×òåíèå ôàéëà: |
1. Ñîõðàíÿåò ñòåê âûçûâàþùåãî êîäà è óñòàíàâëèâàåò ñâîé ñòåê: |
ss:sp = 0:3000, bp=dat: ïàðà ss:bp ïðè ðàáîòå ñ îñòàëüíûì |
êîäîì äîëæíà óêàçûâàòü íà 0:dat. |
2. Ðàçáèðàåò ïåðåäàííûå ïàðàìåòðû è âûçûâàåò ïðîöåäóðó çàãðóçêè ôàéëà. |
3. Âîññòàíàâëèâàåò ñòåê âûçûâàþùåãî êîäà è âîçâðàùàåò óïðàâëåíèå. |
Функция обратного вызова для вторичного загрузчика: |
предоставляет возможность чтения файла. |
Вход и выход описаны в спецификации на загрузчик. |
Чтение файла: |
1. Сохраняет стек вызывающего кода и устанавливает свой стек: |
ss:sp = 0:3000, bp=dat: пара ss:bp при работе с остальным |
кодом должна указывать на 0:dat. |
2. Разбирает переданные параметры и вызывает процедуру загрузки файла. |
3. Восстанавливает стек вызывающего кода и возвращает управление. |
Âñïîìîãàòåëüíûå ïðîöåäóðû. |
Ïðîöåäóðà ÷òåíèÿ ñåêòîðîâ (read): |
íà âõîäå äîëæíî áûòü óñòàíîâëåíî: |
Вспомогательные процедуры. |
Процедура чтения секторов (read): |
на входе должно быть установлено: |
ss:bp = 0:dat |
es:bx = óêàçàòåëü íà íà÷àëî áóôåðà, êóäà áóäóò ïðî÷èòàíû äàííûå |
eax = ñòàðòîâûé ñåêòîð (îòíîñèòåëüíî íà÷àëà ëîãè÷åñêîãî äèñêà) |
cx = ÷èñëî ñåêòîðîâ (äîëæíî áûòü áîëüøå íóëÿ) |
íà âûõîäå: es:bx óêàçûâàåò íà êîíåö áóôåðà, â êîòîðûé áûëè ïðî÷èòàíû äàííûå, |
ôëàã CF óñòàíîâëåí, åñëè âîçíèêëà îøèáêà ÷òåíèÿ |
1. Ïåðåâîäèò ñòàðòîâûé ñåêòîð (îòñ÷èòûâàåìûé îò íà÷àëà òîìà) â ñåêòîð íà |
óñòðîéñòâå, ïðèáàâëÿÿ íîìåð ïåðâîãî ñåêòîðà ëîãè÷åñêîãî äèñêà, |
íàéäåííûé ïðè ïåðåáîðå äèñêîâ. |
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 = указатель на начало буфера, куда будут прочитаны данные |
eax = стартовый сектор (относительно начала логического диска) |
cx = число секторов (должно быть больше нуля) |
на выходе: es:bx указывает на конец буфера, в который были прочитаны данные, |
флаг CF установлен, если возникла ошибка чтения |
1. Переводит стартовый сектор (отсчитываемый от начала тома) в сектор на |
устройстве, прибавляя номер первого сектора логического диска, |
найденный при переборе дисков. |
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. |
Ïðîöåäóðà îáðàáîòêè îøèáîê (find_error_si è find_error_sp): |
íà âõîäå: óêàçàòåëü íà ñîîáùåíèå îá îøèáêå â si ëèáî íà âåðõóøêå ñòåêà |
0. Åñëè âûçûâàåòñÿ find_error_si, îíà ïîìåùàåò ïåðåäàííûé óêàçàòåëü â ñòåê. |
1. Åñëè îøèáêà ïðîèçîøëà â ïðîöåññå ðàáîòû callback-ôóíêöèè, òî |
(ìåòêà error_in_callback) îáðàáîò÷èê ïðîñòî âîçâðàùàåò óïðàâëåíèå |
âûçâàâøåìó êîäó, ðàïîðòóÿ î íåíàéäåííîì ôàéëå. |
2. Åñëè æå îøèáêà ïðîèçîøëà äî ïåðåäà÷è óïðàâëåíèÿ âòîðè÷íîìó çàãðóç÷èêó, |
îáðàáîò÷èê âûâîäèò ñîîáùåíèå òèïà "Error: <òåêóùèé îáúåêò>: <îøèáêà>" |
è (âîññòàíîâèâ ñòåê) ïåðåõîäèò ê ñëåäóþùåìó ëîãè÷åñêîìó äèñêó. |
Процедура обработки ошибок (find_error_si и find_error_sp): |
на входе: указатель на сообщение об ошибке в si либо на верхушке стека |
0. Если вызывается find_error_si, она помещает переданный указатель в стек. |
1. Если ошибка произошла в процессе работы callback-функции, то |
(метка error_in_callback) обработчик просто возвращает управление |
вызвавшему коду, рапортуя о ненайденном файле. |
2. Если же ошибка произошла до передачи управления вторичному загрузчику, |
обработчик выводит сообщение типа "Error: <текущий объект>: <ошибка>" |
и (восстановив стек) переходит к следующему логическому диску. |
Ïðîöåäóðà ÷òåíèÿ ôàéëà/àòðèáóòà ïî èçâåñòíîìó ðàçìåùåíèþ íà äèñêå |
Процедура чтения файла/атрибута по известному размещению на диске |
(read_file_chunk): |
íà âõîäå äîëæíî áûòü óñòàíîâëåíî: |
ds:si = óêàçàòåëü íà èíôîðìàöèþ î ðàçìåùåíèè |
es:bx = óêàçàòåëü íà íà÷àëî áóôåðà, êóäà áóäóò ïðî÷èòàíû äàííûå |
ecx = ëèìèò ÷èñëà ñåêòîðîâ äëÿ ÷òåíèÿ, ñòàðøåå ñëîâî äîëæíî áûòü 0 |
íà âûõîäå: es:bx óêàçûâàåò íà êîíåö áóôåðà, â êîòîðûé áûëè ïðî÷èòàíû äàííûå, |
ôëàã CF óñòàíîâëåí, åñëè âîçíèêëà îøèáêà ÷òåíèÿ |
1. Îïðåäåëÿåò, ÿâëÿåòñÿ ëè àòðèáóò ðåçèäåíòíûì (âîçìîæíî òîëüêî â NTFS |
è îçíà÷àåò, ÷òî äàííûå ôàéëà/àòðèáóòà óæå áûëè öåëèêîì ïðî÷èòàíû ïðè |
îáðàáîòêå èíôîðìàöèè î ôàéëå) èëè íåðåçèäåíòíûì (îçíà÷àåò, ÷òî äàííûå |
õðàíÿòñÿ ãäå-òî íà äèñêå, è èìååòñÿ èíôîðìàöèÿ î òîì, ãäå èìåííî). |
2. Äëÿ ðåçèäåíòíûõ àòðèáóòîâ (ìåòêà read_file_chunk.resident) ïðîñòî êîïèðóåò |
äàííûå ïî ìåñòó íàçíà÷åíèÿ (ñ ó÷¸òîì óêàçàííîãî ëèìèòà). |
3. Äëÿ íåðåçèäåíòíûõ àòðèáóòîâ èíôîðìàöèÿ ñîñòîèò èç ïàð <ðàçìåð î÷åðåäíîãî |
ôðàãìåíòà ôàéëà â êëàñòåðàõ, ñòàðòîâûé êëàñòåð ôðàãìåíòà>; ïðîöåäóðà |
÷èòàåò ôðàãìåíòû, ïîêà ôàéë íå çàêîí÷èòñÿ èëè ïîêà íå áóäåò äîñòèãíóò |
óêàçàííûé ëèìèò. |
на входе должно быть установлено: |
ds:si = указатель на информацию о размещении |
es:bx = указатель на начало буфера, куда будут прочитаны данные |
ecx = лимит числа секторов для чтения, старшее слово должно быть 0 |
на выходе: es:bx указывает на конец буфера, в который были прочитаны данные, |
флаг CF установлен, если возникла ошибка чтения |
1. Определяет, является ли атрибут резидентным (возможно только в NTFS |
и означает, что данные файла/атрибута уже были целиком прочитаны при |
обработке информации о файле) или нерезидентным (означает, что данные |
хранятся где-то на диске, и имеется информация о том, где именно). |
2. Для резидентных атрибутов (метка read_file_chunk.resident) просто копирует |
данные по месту назначения (с учётом указанного лимита). |
3. Для нерезидентных атрибутов информация состоит из пар <размер очередного |
фрагмента файла в кластерах, стартовый кластер фрагмента>; процедура |
читает фрагменты, пока файл не закончится или пока не будет достигнут |
указанный лимит. |
Ïðîöåäóðà ïðîñìîòðà êýøà (cache_lookup): |
íà âõîäå äîëæíî áûòü óñòàíîâëåíî: |
eax = èñêîìîå çíà÷åíèå |
ss:si = óêàçàòåëü íà ñòðóêòóðó-çàãîëîâîê êýøà |
íà âûõîäå: ss:di = óêàçàòåëü íà âõîä â êýøå; ôëàã CF óñòàíîâëåí, åñëè çíà÷åíèå |
áûëî òîëüêî ÷òî äîáàâëåíî, è ñáðîøåí, åñëè îíî óæå áûëî â êýøå. |
1. Ïðîñìàòðèâàåò êýø â ïîèñêàõ óêàçàííîãî çíà÷åíèÿ. Åñëè çíà÷åíèå íàéäåíî |
(ïðè ýòîì ôëàã CF îêàçûâàåòñÿ ñáðîøåííûì), ïåðåõîäèò ê øàãó 4. |
2. Åñëè êýø óæå çàïîëíåí, óäàëÿåò èç êýøà ñàìûé ñòàðûé âõîä (îí íàõîäèòñÿ â |
ãîëîâå äâóñâÿçíîãî ñïèñêà), èíà÷å äîáàâëÿåò ê êýøó åù¸ îäèí âõîä. |
3. Óñòàíàâëèâàåò â ïîëó÷åííîì âõîäå óêàçàííîå çíà÷åíèå. Óñòàíàâëèâàåò ôëàã |
CF, ïîñëåäóþùèå øàãè íå ìåíÿþò ñîñòîÿíèÿ ôëàãîâ. Ïåðåõîäèò ê øàãó 5. |
4. Óäàëÿåò âõîä èç ñïèñêà. |
5. Äîáàâëÿåò ñåêòîð â êîíåö ñïèñêà (ñàìûé íîâûé âõîä). |
Процедура просмотра кэша (cache_lookup): |
на входе должно быть установлено: |
eax = искомое значение |
ss:si = указатель на структуру-заголовок кэша |
на выходе: ss:di = указатель на вход в кэше; флаг CF установлен, если значение |
было только что добавлено, и сброшен, если оно уже было в кэше. |
1. Просматривает кэш в поисках указанного значения. Если значение найдено |
(при этом флаг CF оказывается сброшенным), переходит к шагу 4. |
2. Если кэш уже заполнен, удаляет из кэша самый старый вход (он находится в |
голове двусвязного списка), иначе добавляет к кэшу ещё один вход. |
3. Устанавливает в полученном входе указанное значение. Устанавливает флаг |
CF, последующие шаги не меняют состояния флагов. Переходит к шагу 5. |
4. Удаляет вход из списка. |
5. Добавляет сектор в конец списка (самый новый вход). |
/kernel/branches/Kolibri-acpi/bootloader/extended_primary_loader/cdfs/bootsect.txt |
---|
26,393 → 26,393 |
Sector not found. N. N.N.N. N.N.N.N.N.N.N. N.N. N.N.N.N.N.N.? |
Áóòñåêòîð äëÿ çàãðóçêè ñ CD/DVD ñ ôàéëîâîé ñèñòåìîé ISO-9660. |
(ISO-9660 è å¸ ðàñøèðåíèÿ - ñòàíäàðò äëÿ CD; DVD ìîæåò èñïîëüçîâàòü |
ëèáî ISO-9660, ëèáî UDF.) |
Бутсектор для загрузки с CD/DVD с файловой системой ISO-9660. |
(ISO-9660 и её расширения - стандарт для CD; DVD может использовать |
либо ISO-9660, либо UDF.) |
===================================================================== |
Òðåáîâàíèÿ äëÿ ðàáîòû: |
1) Ñàì áóòñåêòîð è âñå èñïîëüçóåìûå ôàéëû äîëæíû áûòü ÷èòàáåëüíû. |
2) Ìèíèìàëüíûé ïðîöåññîð - 80386. |
3) Â ñèñòåìå äîëæíî áûòü êàê ìèíèìóì 452K ñâîáîäíîé áàçîâîé ïàìÿòè. |
Требования для работы: |
1) Сам бутсектор и все используемые файлы должны быть читабельны. |
2) Минимальный процессор - 80386. |
3) В системе должно быть как минимум 452K свободной базовой памяти. |
===================================================================== |
Äîêóìåíòàöèÿ â òåìó (ññûëêè ïðîâåðÿëèñü íà âàëèäíîñòü 14.09.2008): |
ñòàíäàðò ISO-9660: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-119.pdf |
ñòàíäàðò çàãðóçî÷íîãî CD: http://www.phoenix.com/NR/rdonlyres/98D3219C-9CC9-4DF5-B496-A286D893E36A/0/specscdrom.pdf |
îôèöèàëüíàÿ ñïåöèôèêàöèÿ ðàñøèðåíèÿ 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 |
Документация в тему (ссылки проверялись на валидность 14.09.2008): |
стандарт ISO-9660: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-119.pdf |
стандарт загрузочного CD: http://www.phoenix.com/NR/rdonlyres/98D3219C-9CC9-4DF5-B496-A286D893E36A/0/specscdrom.pdf |
официальная спецификация расширения 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 |
===================================================================== |
Ñõåìà èñïîëüçóåìîé ïàìÿòè: |
1000-1800 âðåìåííûé áóôåð äëÿ ÷òåíèÿ îäèíî÷íûõ ñåêòîðîâ |
...-7C00 ñòåê |
7C00-8400 êîä áóòñåêòîðà |
8400-8A00 èíôîðìàöèÿ î êýøå äëÿ ïàïîê: ìàññèâ âõîäîâ ñëåäóþùåãî |
ôîðìàòà: |
dw ñëåäóþùèé ýëåìåíò â L2-ñïèñêå çàêýøèðîâàííûõ ïàïîê, |
óïîðÿäî÷åííîì ïî âðåìåíè èñïîëüçîâàíèÿ |
(ãîëîâà ñïèñêà - ñàìûé ñòàðûé); |
dw ïðåäûäóùèé ýëåìåíò â òîì æå ñïèñêå; |
dd ïåðâûé ñåêòîð ïàïêè; |
dw ðàçìåð ïàïêè â áàéòàõ; |
dw ñåãìåíò êýøà |
60000-... ñîäåðæèìîå Path Table, åñëè îíà èñïîëüçóåòñÿ |
+ êýø äëÿ ïàïîê; |
òî÷íûé ðàçìåð îïðåäåëÿåòñÿ ðàçìåðîì äîñòóïíîé |
ôèçè÷åñêîé ïàìÿòè - êàê ïðàâèëî, íåïîñðåäñòâåííî |
ïåðåä A0000 ðàçìåùàåòñÿ EBDA, Extended BIOS Data Area |
Схема используемой памяти: |
1000-1800 временный буфер для чтения одиночных секторов |
...-7C00 стек |
7C00-8400 код бутсектора |
8400-8A00 информация о кэше для папок: массив входов следующего |
формата: |
dw следующий элемент в L2-списке закэшированных папок, |
упорядоченном по времени использования |
(голова списка - самый старый); |
dw предыдущий элемент в том же списке; |
dd первый сектор папки; |
dw размер папки в байтах; |
dw сегмент кэша |
60000-... содержимое Path Table, если она используется |
+ кэш для папок; |
точный размер определяется размером доступной |
физической памяти - как правило, непосредственно |
перед A0000 размещается EBDA, Extended BIOS Data Area |
===================================================================== |
Îñíîâíîé ïðîöåññ çàãðóçêè. |
Òî÷êà âõîäà (start): ïîëó÷àåò óïðàâëåíèå îò BIOS ïðè çàãðóçêå, ïðè ýòîì |
dl ñîäåðæèò èäåíòèôèêàòîð äèñêà, ñ êîòîðîãî èä¸ò çàãðóçêà |
1. Ïðè ïåðåäà÷å óïðàâëåíèÿ çàãðóçî÷íîìó êîäó â ñëó÷àå CD/DVD ïàðà cs:ip |
ðàâíà íå 0:7C00, à íà 07C0:0000. Ïîýòîìó ñíà÷àëà çàãðóç÷èê äåëàåò |
äàëüíèé ïðûæîê íà ñàìîãî ñåáÿ ñ öåëüþ ïîëó÷èòü cs=0 (â íåêîòîðûõ |
ìåñòàõ èñïîëüçóåòñÿ àäðåñàöèÿ ïåðåìåííûõ çàãðóç÷èêà ÷åðåç cs, ïîñêîëüêó |
è ds, è es ìîãóò áûòü çàíÿòû ïîä äðóãèå ñåãìåíòû). |
2. Íàñòðàèâàåò ñòåê ss:sp = 0:7C00 (íåïîñðåäñòâåííî ïåðåä îñíîâíûì êîäîì) |
è ñåãìåíòíûå ðåãèñòðû ds=es=0. Ôîðñèðóåò ñáðîøåííûé ôëàã íàïðàâëåíèÿ |
è ðàçðåø¸ííûå ïðåðûâàíèÿ. Ñîõðàíÿåò èäåíòèôèêàòîð çàãðóçî÷íîãî äèñêà |
â ñïåöèàëüíóþ ïåðåìåííóþ. |
3. Ïðîâåðÿåò ïîääåðæêó LBA. Äëÿ CD/DVD íîñèòåëÿ BIOS îáÿçàíà ïðåäîñòàâëÿòü |
LBA-ôóíêöèè. |
4. Èùåò îïèñàòåëü òîìà CD (Primary Volume Descriptor, PVD): ïî ñòàíäàðòó |
ISO9660 ñî ñìåùåíèÿ 10h íà÷èíàåòñÿ öåïî÷êà îïèñàòåëåé òîìà, |
çàâåðøàþùàÿñÿ ñïåöèàëüíûì îïèñàòåëåì (Volume Descriptor Set |
Terminator). Êîä ïî î÷åðåäè ñ÷èòûâàåò âñå ñåêòîðà, ïîêà íå íàòêí¸òñÿ |
ëèáî íà èñêîìûé îïèñàòåëü, ëèáî íà òåðìèíàòîð. Âî âòîðîì ñëó÷àå |
âûäà¸òñÿ ñîîòâåòñòâóþùåå ñîîáùåíèå, è çàãðóçêà ïðåêðàùàåòñÿ. |
Âîîáùå ãîâîðÿ, â ñëó÷àå ìóëüòèñåññèîííûõ CD îñíîâíîé êàòàëîã ñîäåðæèìîãî CD |
ðàñïîëàãàåòñÿ â ïîñëåäíåé ñåññèè. È ñïåöèôèêàöèÿ ElTorito çàãðóçî÷íîãî |
CD îïåðèðóåò òàêæå ñ ïîñëåäíåé ñåññèåé. Îäíàêî íà ïðàêòèêå îêàçûâàåòñÿ, |
÷òî: âî-ïåðâûõ, ðåàëüíûå BIOSû íå ïîíèìàþò ìóëüòèñåññèîííûõ CD è |
âñåãäà èñïîëüçóþò ïåðâóþ ñåññèþ; âî-âòîðûõ, BIOSîâñêèé int 13h ïðîñòî |
íå ïîçâîëÿåò ïîëó÷èòü èíôîðìàöèþ î ïîñëåäíåé ñåññèè.  ñâÿçè ñ ýòèì |
çàãðóç÷èê òàêæå èñïîëüçóåò ïåðâóþ ñåññèþ. (Â-òðåòüèõ, â îäíîé èç BIOS |
îáíàðóæèëàñü çàãîòîâêà, êîòîðàÿ â ñëó÷àå çàïðîñà ñåêòîðà 10h, â êîòîðîì |
âî âñåõ íîðìàëüíûõ ñëó÷àÿõ è ðàñïîëàãàåòñÿ PVD, ïåðåíàïðàâëÿåò åãî |
íà ñåêòîð 10h+(íà÷àëî ñåññèè). Åñëè áû ýòîò BIOS åù¸ è ãðóçèëñÿ ñ |
ïîñëåäíåé ñåññèè, òî áëàãîäàðÿ çàãîòîâêå çàãðóç÷èê áåç âñÿêèõ |
ìîäèôèêàöèé òàêæå ÷èòàë áû ïîñëåäíþþ ñåññèþ.) |
5. (ìåòêà pvd_found) Ñ÷èòûâàåò èç PVD íåêîòîðóþ èíôîðìàöèþ î òîìå âî |
âíóòðåííèå ïåðåìåííûå: ðàçìåð ëîãè÷åñêîãî áëîêà (ñîãëàñíî ñïåöèôèêàöèè, |
äîëæåí áûòü ñòåïåíüþ äâîéêè îò 512 äî ðàçìåðà ëîãè÷åñêîãî ñåêòîðà, |
ðàâíîãî 2048 äëÿ CD è DVD); ïîëîæåíèå íà äèñêå êîðíåâîé ïàïêè; |
âû÷èñëÿåò ÷èñëî áëîêîâ â ñåêòîðå (èç ïðåäûäóùåãî ïðèìå÷àíèÿ ñëåäóåò, |
÷òî îíî âñåãäà öåëîå è ñàìî ÿâëÿåòñÿ ñòåïåíüþ äâîéêè). |
6. Ïîëó÷àåò ðàçìåð áàçîâîé ïàìÿòè âûçîâîì int 12h; íà åãî îñíîâå âû÷èñëÿåò |
ðàçìåð ïðîñòðàíñòâà, êîòîðîå ìîæåò èñïîëüçîâàòü çàãðóç÷èê (îò |
àäðåñà 6000:0000 äî êîíöà äîñòóïíîé ïàìÿòè). |
7. Çàãðóæàåò òàáëèöó ïóòåé CD (Path Table) - îáëàñòü äàííûõ, êîòîðàÿ ñîäåðæèò |
áàçîâóþ èíôîðìàöèþ îáî âñåõ ïàïêàõ íà äèñêå. Åñëè òàáëèöà ñëèøêîì |
âåëèêà (áîëüøå 62K èëè áîëüøå ïîëîâèíû äîñòóïíîé ïàìÿòè), òî îíà |
èãíîðèðóåòñÿ. Åñëè òàáëèöà ïóòåé íåäîñòóïíà, òî çàïðîñ òèïà |
dir1/dir2/dir3/file ïðèâåä¸ò ê ïîñëåäîâàòåëüíîìó ðàçáîðó êîðíåâîé |
ïàïêè è ïàïîê dir1,dir2,dir3; åñëè äîñòóïíà, òî äîñòàòî÷íî ðàçîáðàòü |
ñàìó òàáëèöó ïóòåé (ãäå çàïèñàíî ïîëîæåíèå ïàïêè dir1/dir2/dir3) |
è ïàïêó dir3. Åñëè òàáëèöà çàãðóæåíà, òî ñîîòâåòñòâåííî óìåíüøàåòñÿ |
îáú¸ì îñòàâøåéñÿ äîñòóïíîé ïàìÿòè è óâåëè÷èâàåòñÿ óêàçàòåëü íà |
ñâîáîäíóþ îáëàñòü. |
8. Çàïîìèíàåò îáùèé ðàçìåð è íà÷àëî êýøà äëÿ ïàïîê (âñÿ îñòàâøàÿñÿ ïîñëå ï.7 |
äîñòóïíàÿ ïàìÿòü îòâîäèòñÿ ïîä ýòîò êýø). |
9. Âûäà¸ò çàïðîñ íà ÷òåíèå ôàéëà âòîðè÷íîãî çàãðóç÷èêà kord/loader. Ïðè îøèáêå |
ïå÷àòàåò ñîîòâåòñòâóþùåå ñîîáùåíèå è ïðåêðàùàåò çàãðóçêó ñ CD. |
10. Óñòàíàâëèâàåò ðåãèñòðû äëÿ âòîðè÷íîãî çàãðóç÷èêà: al='c' èäåíòèôèöèðóåò |
òèï óñòðîéñòâà - CD/DVD; ah=BIOS-èäåíòèôèêàòîð äèñêà; bx='is' |
èäåíòèôèöèðóåò ôàéëîâóþ ñèñòåìó ISO-9660; ds:si óêàçûâàåò íà |
callback-ôóíêöèþ, êîòîðóþ ìîæåò âûçûâàòü âòîðè÷íûé çàãðóç÷èê. |
11. Ïåðåäà¸ò óïðàâëåíèå âòîðè÷íîìó çàãðóç÷èêó, ñîâåðøàÿ äàëüíèé ïðûæîê |
íà àäðåñ, êóäà kord/loader áûë çàãðóæåí. |
Основной процесс загрузки. |
Точка входа (start): получает управление от BIOS при загрузке, при этом |
dl содержит идентификатор диска, с которого идёт загрузка |
1. При передаче управления загрузочному коду в случае CD/DVD пара cs:ip |
равна не 0:7C00, а на 07C0:0000. Поэтому сначала загрузчик делает |
дальний прыжок на самого себя с целью получить cs=0 (в некоторых |
местах используется адресация переменных загрузчика через cs, поскольку |
и ds, и es могут быть заняты под другие сегменты). |
2. Настраивает стек ss:sp = 0:7C00 (непосредственно перед основным кодом) |
и сегментные регистры ds=es=0. Форсирует сброшенный флаг направления |
и разрешённые прерывания. Сохраняет идентификатор загрузочного диска |
в специальную переменную. |
3. Проверяет поддержку LBA. Для CD/DVD носителя BIOS обязана предоставлять |
LBA-функции. |
4. Ищет описатель тома CD (Primary Volume Descriptor, PVD): по стандарту |
ISO9660 со смещения 10h начинается цепочка описателей тома, |
завершающаяся специальным описателем (Volume Descriptor Set |
Terminator). Код по очереди считывает все сектора, пока не наткнётся |
либо на искомый описатель, либо на терминатор. Во втором случае |
выдаётся соответствующее сообщение, и загрузка прекращается. |
Вообще говоря, в случае мультисессионных CD основной каталог содержимого CD |
располагается в последней сессии. И спецификация ElTorito загрузочного |
CD оперирует также с последней сессией. Однако на практике оказывается, |
что: во-первых, реальные BIOSы не понимают мультисессионных CD и |
всегда используют первую сессию; во-вторых, BIOSовский int 13h просто |
не позволяет получить информацию о последней сессии. В связи с этим |
загрузчик также использует первую сессию. (В-третьих, в одной из BIOS |
обнаружилась заготовка, которая в случае запроса сектора 10h, в котором |
во всех нормальных случаях и располагается PVD, перенаправляет его |
на сектор 10h+(начало сессии). Если бы этот BIOS ещё и грузился с |
последней сессии, то благодаря заготовке загрузчик без всяких |
модификаций также читал бы последнюю сессию.) |
5. (метка pvd_found) Считывает из PVD некоторую информацию о томе во |
внутренние переменные: размер логического блока (согласно спецификации, |
должен быть степенью двойки от 512 до размера логического сектора, |
равного 2048 для CD и DVD); положение на диске корневой папки; |
вычисляет число блоков в секторе (из предыдущего примечания следует, |
что оно всегда целое и само является степенью двойки). |
6. Получает размер базовой памяти вызовом int 12h; на его основе вычисляет |
размер пространства, которое может использовать загрузчик (от |
адреса 6000:0000 до конца доступной памяти). |
7. Загружает таблицу путей CD (Path Table) - область данных, которая содержит |
базовую информацию обо всех папках на диске. Если таблица слишком |
велика (больше 62K или больше половины доступной памяти), то она |
игнорируется. Если таблица путей недоступна, то запрос типа |
dir1/dir2/dir3/file приведёт к последовательному разбору корневой |
папки и папок dir1,dir2,dir3; если доступна, то достаточно разобрать |
саму таблицу путей (где записано положение папки dir1/dir2/dir3) |
и папку dir3. Если таблица загружена, то соответственно уменьшается |
объём оставшейся доступной памяти и увеличивается указатель на |
свободную область. |
8. Запоминает общий размер и начало кэша для папок (вся оставшаяся после п.7 |
доступная память отводится под этот кэш). |
9. Выдаёт запрос на чтение файла вторичного загрузчика kord/loader. При ошибке |
печатает соответствующее сообщение и прекращает загрузку с CD. |
10. Устанавливает регистры для вторичного загрузчика: al='c' идентифицирует |
тип устройства - CD/DVD; ah=BIOS-идентификатор диска; bx='is' |
идентифицирует файловую систему ISO-9660; ds:si указывает на |
callback-функцию, которую может вызывать вторичный загрузчик. |
11. Передаёт управление вторичному загрузчику, совершая дальний прыжок |
на адрес, куда kord/loader был загружен. |
Ôóíêöèÿ îáðàòíîãî âûçîâà äëÿ âòîðè÷íîãî çàãðóç÷èêà (callback): |
ïðåäîñòàâëÿåò âîçìîæíîñòü ÷òåíèÿ ôàéëà. |
Âõîä è âûõîä îïèñàíû â ñïåöèôèêàöèè íà çàãðóç÷èê. |
Ïåðåíàïðàâëÿåò çàïðîñ ñîîòâåòñòâóþùåé ëîêàëüíîé ïðîöåäóðå (load_file ïðè |
ïåðâîì çàïðîñå íà çàãðóçêó ôàéëà, loadloop.loadnew ïðè ïîñëåäóþùèõ |
çàïðîñàõ íà ïðîäîëæåíèå çàãðóçêè ôàéëà). |
Функция обратного вызова для вторичного загрузчика (callback): |
предоставляет возможность чтения файла. |
Вход и выход описаны в спецификации на загрузчик. |
Перенаправляет запрос соответствующей локальной процедуре (load_file при |
первом запросе на загрузку файла, loadloop.loadnew при последующих |
запросах на продолжение загрузки файла). |
Âñïîìîãàòåëüíûå ïðîöåäóðû. |
Êîä îáðàáîòêè îøèáîê (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): |
íà âõîäå äîëæíî áûòü óñòàíîâëåíî: |
es:bx = óêàçàòåëü íà íà÷àëî áóôåðà, êóäà áóäóò ïðî÷èòàíû äàííûå |
eax = ñòàðòîâûé ñåêòîð |
cx = ÷èñëî ñåêòîðîâ |
íà âûõîäå: |
es:bx óêàçûâàåò íà êîíåö áóôåðà, â êîòîðûé áûëè ïðî÷èòàíû äàííûå |
åñëè ïðîèçîøëà îøèáêà ÷òåíèÿ, ôëàã CF óñòàíîâëåí |
1.  öèêëå (øàãè 2-4) ÷èòàåò ñåêòîðû, ñëåäèò çà òåì, ÷òîáû íà êàæäîé èòåðàöèè |
÷èñëî ÷èòàåìûõ ñåêòîðîâ íå ïðåâîñõîäèëî 7Fh (òðåáîâàíèå ñïåöèôèêàöèè |
Процедура чтения секторов (read_sectors): |
на входе должно быть установлено: |
es:bx = указатель на начало буфера, куда будут прочитаны данные |
eax = стартовый сектор |
cx = число секторов |
на выходе: |
es:bx указывает на конец буфера, в который были прочитаны данные |
если произошла ошибка чтения, флаг CF установлен |
1. В цикле (шаги 2-4) читает секторы, следит за тем, чтобы на каждой итерации |
число читаемых секторов не превосходило 7Fh (требование спецификации |
EDD BIOS). |
2. Åñëè ÷èñëî ñåêòîðîâ äëÿ ÷òåíèÿ áîëüøå 7Fh, óìåíüøàåò åãî (äëÿ òåêóùåé |
èòåðàöèè) äî 7Fh. |
3. Ôîðìèðóåò â ñòåêå ïàêåò äëÿ int 13h (êëàä¸ò âñå íóæíûå äàííûå êîìàíäàìè |
push, ïðè÷¸ì â îáðàòíîì ïîðÿäêå: ñòåê - ñòðóêòóðà LIFO, è äàííûå â |
ñòåêå õðàíÿòñÿ â îáðàòíîì ïîðÿäêå ïî îòíîøåíèþ ê òîìó, êàê èõ òóäà |
êëàëè). |
4. Âûçûâàåò BIOS. Åñëè BIOS ðàïîðòóåò îá îøèáêå, î÷èùàåò ñòåê, |
óñòàíàâëèâàåò CF=1 è âûõîäèò èç ïðîöåäóðû. |
Î÷èùàåò ñòåê îò ïàêåòà, ñôîðìèðîâàííîãî íà ïðåäûäóùåì øàãå. |
5.  ñîîòâåòñòâèè ñ ÷èñëîì ïðî÷èòàííûõ íà òåêóùåé èòåðàöèè ñåêòîðîâ |
êîððåêòèðóåò òåêóùèé ñåêòîð, ÷èñëî îñòàâøèõñÿ ñåêòîðîâ è óêàçàòåëü íà |
áóôåð (â ïàðå es:bx êîððåêòèðóåòñÿ es). Åñëè âñ¸ ïðî÷èòàíî, çàêàí÷èâàåò |
ðàáîòó, èíà÷å âîçâðàùàåòñÿ íà øàã 2. |
2. Если число секторов для чтения больше 7Fh, уменьшает его (для текущей |
итерации) до 7Fh. |
3. Формирует в стеке пакет для int 13h (кладёт все нужные данные командами |
push, причём в обратном порядке: стек - структура LIFO, и данные в |
стеке хранятся в обратном порядке по отношению к тому, как их туда |
клали). |
4. Вызывает BIOS. Если BIOS рапортует об ошибке, очищает стек, |
устанавливает CF=1 и выходит из процедуры. |
Очищает стек от пакета, сформированного на предыдущем шаге. |
5. В соответствии с числом прочитанных на текущей итерации секторов |
корректирует текущий сектор, число оставшихся секторов и указатель на |
буфер (в паре es:bx корректируется es). Если всё прочитано, заканчивает |
работу, иначе возвращается на шаг 2. |
Ïðîöåäóðà âûâîäà íà ýêðàí ASCIIZ-ñòðîêè (out_string): |
íà âõîäå: ds:si -> ñòðîêà |
 öèêëå, ïîêà íå äîñòèãíóò çàâåðøàþùèé íîëü, âûçûâàåò ôóíêöèþ int 10h/ah=0Eh. |
Процедура вывода на экран ASCIIZ-строки (out_string): |
на входе: ds:si -> строка |
В цикле, пока не достигнут завершающий ноль, вызывает функцию int 10h/ah=0Eh. |
Ïðîöåäóðà çàãðóçêè ôàéëà (load_file): |
íà âõîäå: |
ds:di = óêàçàòåëü íà èíôîðìàöèîííóþ ñòðóêòóðó, îïèñàííóþ â ñïåöèôèêàöèè |
íà çàãðóç÷èê, à òàêæå â êîììåíòàðèÿõ ê êîäó |
íà âûõîäå: |
bx = ñòàòóñ: 0=óñïåõ, 1=ôàéë ñëèøêîì áîëüøîé, ïðî÷èòàíà òîëüêî ÷àñòü, |
2=ôàéë íå íàéäåí, 3=îøèáêà ÷òåíèÿ |
dx:ax = ðàçìåð ôàéëà, 0xFFFFFFFF, åñëè ôàéë íå íàéäåí |
1. Åñëè ïîäãîòîâèòåëüíûé êîä çàãðóçèë òàáëèöó ïóòåé, òî èùåò ïàïêó â òàáëèöå, |
èíà÷å ïåðåõîäèò ñðàçó ê øàãó 4, óñòàíîâèâ eax = íà÷àëüíûé áëîê |
êîðíåâîé ïàïêè. |
2. Óñòàíàâëèâàåò es:di íà íà÷àëî òàáëèöû ïóòåé. Îãðàíè÷åíèå íà ðàçìåð |
ãàðàíòèðóåò, ÷òî âñÿ òàáëèöà ïîìåùàåòñÿ â ñåãìåíòå 6000h. |
Èíèöèàëèçèðóåò dx (â êîòîðîì áóäåò õðàíèòñÿ íîìåð òåêóùåãî âõîäà â |
òàáëèöå, ñ÷èòàÿ ñ 1), cx (ðàçìåð îñòàâøåãîñÿ ó÷àñòêà òàáëèöû), |
bx (íîìåð âõîäà, ñîîòâåòñòâóþùåãî ðîäèòåëüñêîé ïàïêå äëÿ òåêóùåãî |
ðàññìàòðèâàåìîãî ó÷àñòêà ïóòè). |
3. Â öèêëå èùåò âõîä ñ íóæíûì ðîäèòåëüñêèì ýëåìåíòîì è íóæíûì èìåíåì. Ýëåìåíòû |
òàáëèöû ïóòåé óïîðÿäî÷åíû (ïîäðîáíî î ïîðÿäêå íàïèñàíî â ñïåöèôèêàöèè), |
òàê ÷òî åñëè ðîäèòåëüñêèé ýëåìåíò äëÿ î÷åðåäíîãî âõîäà áîëüøå íóæíîãî, |
òî íóæíîãî âõîäà â òàáëèöå íåò ñîâñåì, è â ýòîì ñëó÷àå ïðîèñõîäèò |
âûõîä èç ïðîöåäóðû ñ bx=2, ax=dx=0xFFFF. Åñëè îáíàðóæèëñÿ ýëåìåíò, |
ñîîòâåòñòâóþùèé î÷åðåäíîé ïàïêå â çàïðîøåííîì ïóòè, òî íà ðàññìîòðåíèå |
âûíîñèòñÿ ñëåäóþùàÿ êîìïîíåíòà ïóòè. Åñëè ýòà êîìïîíåíòà ïîñëåäíÿÿ, |
òî îñòàëîñü íàéòè ôàéë â ïàïêå, è êîä ïåðåõîäèò ê ïóíêòó 4, |
óñòàíîâèâ eax = íà÷àëüíûé áëîê ýòîé ïàïêè. Åñëè æå íåò, òî ýòà |
êîìïîíåíòà äîëæíà çàäàâàòü èìÿ ïàïêè, è êîä âîçâðàùàåòñÿ ê ïóíêòó 3, |
ñêîððåêòèðîâàâ óêàçàòåëü íà èìÿ ds:si è íîìåð ðîäèòåëüñêîãî âõîäà bx. |
4. (parse_dir) Íà ýòîì øàãå çàäàíû íà÷àëüíûé ëîãè÷åñêèé áëîê ïàïêè â eax |
è óêàçàòåëü íà èìÿ ôàéëà îòíîñèòåëüíî ýòîé ïàïêè â ds:si. Åñëè |
ïàïêó èñêàëè ïî òàáëèöå ïóòåé, òî èìÿ ôàéëà óæå íå ñîäåðæèò ïîäïàïîê; |
åñëè æå íåò, òî ïîäïàïêè âïîëíå âîçìîæíû. |
5. Ôàéëû â ISO-9660 ìîãóò ñîñòîÿòü èç íåñêîëüêèõ êóñêîâ (File Section), êàæäûé |
èç êîòîðûõ çàäà¸òñÿ îòäåëüíûì âõîäîì â ïàïêå. Èíôîðìàöèÿ îáî âñåõ |
òàêèõ êóñêàõ ïðè ïðîñìîòðå ïàïêè çàïîìèíàåòñÿ â îáëàñòè, íà÷èíàþùåéñÿ |
ñ àäðåñà 0000:2000. Ïåðåìåííàÿ cur_desc_end ñîäåðæèò óêàçàòåëü íà |
êîíåö ýòîé îáëàñòè, îí æå óêàçàòåëü, êóäà áóäåò ïîìåùåíà èíôîðìàöèÿ |
ïðè îáíàðóæåíèè ñëåäóþùåãî âõîäà. (Ïàïêè, ñîãëàñíî ñïåöèôèêàöèè, |
äîëæíû çàäàâàòüñÿ îäíèì êóñêîì.) |
6. Êîä ñíà÷àëà èùåò çàïðîøåííóþ ïàïêó â êýøå ïàïîê. |
7. (parse_dir.found) Åñëè ïàïêà óæå åñòü â êýøå, òî îíà óäàëÿåòñÿ èç ñïèñêà, |
îòñîðòèðîâàííîãî ïî äàâíîñòè ïîñëåäíåãî îáðàùåíèÿ è êîä ïåðåõîäèò ê |
ï.15. (Ñëåäóþùèì äåéñòâèåì ñòàíåò äîáàâëåíèå ïàïêè â êîíåö ñïèñêà.) |
8. (parse_dir.notfound) Åñëè æå ïàïêè íåò â êýøå, òî å¸ ïðèä¸òñÿ çàãðóæàòü |
ñ äèñêà. Ñíà÷àëà çàãðóæàåòñÿ ïåðâûé ñåêòîð (ôèçè÷åñêèé ñåêòîð, |
ñîäåðæàùèé ïåðâûé ëîãè÷åñêèé áëîê). Ïðè îøèáêå ââîäà/âûâîäà |
ïðîèñõîäèò íåìåäëåííûé âûõîä èç ïðîöåäóðû ñ bx=3, dx=ax=0xFFFF. |
Ïåðâûé ýëåìåíò ïàïêè ñîäåðæèò èíôîðìàöèþ î ñàìîé ýòîé ïàïêå, êîíêðåòíî |
çàãðóç÷èê èíòåðåñóåòñÿ å¸ ðàçìåðîì. |
9. Åñëè ðàçìåð ïàïêè ñëèøêîì áîëüøîé (áîëüøå èëè ðàâåí 64K ëèáî áîëüøå ïîëîâèíû |
îáùåãî ðàçìåðà êýøà), òî êýøèðîâàòüñÿ îíà íå áóäåò.  ýòîì ñëó÷àå êîä |
ñ÷èòûâàåò ïàïêó ïîñåêòîðíî âî âðåìåííûé áóôåð (0000:1000) è ïîñåêòîðíî |
ñêàíèðóåò íà íàëè÷èå çàïðîøåííîãî èìåíè, ïîêà íå íàéä¸ò òàêîãî èìåíè |
èëè ïîêà íå êîí÷àòñÿ äàííûå. (Öèêë íà÷èíàåòñÿ ñî ñêàíèðîâàíèÿ, |
ïîñêîëüêó ïåðâàÿ ÷àñòü äàííûõ óæå ïðî÷èòàíà.)  êîíöå êîä ïåðåõîäèò |
ê ï.17. |
10. (parse_dir.yescache) Åñëè ïðèíÿòî ðåøåíèå î êýøèðîâàíèè ïàïêè, òî íóæíî |
îáåñïå÷èòü äîñòàòî÷íîå êîëè÷åñòâî ñâîáîäíîãî ìåñòà. Äëÿ ýòîãî ìîæåò |
ïîíàäîáèòüñÿ âûêèíóòü êàêîå-òî êîëè÷åñòâî ñòàðûõ äàííûõ (öèêë |
parse_dir.freeloop). Íî åñëè ïðîñòî âûêèäûâàòü, òî, âîîáùå ãîâîðÿ, |
ñâîáîäíîå ïðîñòðàíñòâî îêàæåòñÿ ðàçîðâàííûì íà íåñêîëüêî ôðàãìåíòîâ. |
Ïîýòîìó ïðè âûêèäûâàíèè êàêîé-òî ïàïêè èç êýøà çàãðóç÷èê ïåðåìåùàåò |
âñå ñëåäóþùèå çà íåé äàííûå íàçàä ïî ïàìÿòè è ñîîòâåòñòâåííî |
êîððåêòèðóåò èíôîðìàöèþ î ìåñòîíàõîæäåíèè äàííûõ â èíôîðìàöèè î êýøå. |
Ïðè ýòîì íîâîå ïðîñòðàíñòâî âñåãäà äîáàâëÿåòñÿ â êîíåö äîñòóïíîé |
ïàìÿòè. Öèêë âûêèäûâàíèÿ ïðîäîëæàåòñÿ, ïîêà íå îñâîáîäèòñÿ ìåñòî, |
äîñòàòî÷íîå äëÿ õðàíåíèÿ ïàïêè. Èç-çà îãðàíè÷åíèé íà ðàçìåð êýøèðóåìûõ |
ïàïîê â êîíöå êîíöîâ ìåñòî íàéä¸òñÿ. |
11. Âûäåëÿåòñÿ íîâûé ýëåìåíò êýøà. Âñå óäàë¸ííûå íà øàãå 10 ýëåìåíòû |
îðãàíèçóþòñÿ â åäèíûé ñïèñîê ñâîáîäíûõ ýëåìåíòîâ; åñëè îí íåïóñò, |
òî î÷åðåäíîé ýëåìåíò áåð¸òñÿ èç ýòîãî ñïèñêà; åñëè æå ïóñò, òî |
áåð¸òñÿ ñîâñåì íîâûé ýëåìåíò èç îáëàñòè ïàìÿòè, ïðåäíàçíà÷åííîé äëÿ |
ýëåìåíòîâ êýøà. |
12.  íîâîì ýëåìåíòå çàïîëíÿþòñÿ ïîëÿ íà÷àëüíîãî áëîêà, ñåãìåíòà ñ äàííûìè, |
ðàçìåðà â áàéòàõ. |
13. Óæå ïðî÷èòàííûå äàííûå ïåðâîãî ôèçè÷åñêîãî ñåêòîðà ïåðåñûëàþòñÿ íà |
çàêîííîå ìåñòî â êýøå. |
14. Åñëè âñå äàííûå íå èñ÷åðïûâàþòñÿ ïåðâûì ñåêòîðîì, òî äîãðóæàþòñÿ îñòàâøèåñÿ |
äàííûå ñ äèñêà. Ïðè îøèáêå ÷òåíèÿ, êàê è ðàíüøå, ïðîèñõîäèò âûõîä èç |
ïðîöåäóðû ñ bx=3, ax=dx=0xFFFF. |
15. (parse_dir.scan) Íîâûé ýëåìåíò äîáàâëÿåòñÿ â êîíåö ñïèñêà âñåõ ýëåìåíòîâ |
êýøà. |
16. Çàãðóç÷èê èùåò çàïðîøåííîå èìÿ â çàãðóæåííûõ äàííûõ ïàïêè. |
(Èç-çà îãðàíè÷åíèé íà ðàçìåð êýøèðóåìîé ïàïêè âñå äàííûå ðàñïîëàãàþòñÿ |
â îäíîì ñåãìåíòå.) |
17. (parse_dir.scandone) Åñëè â ïðîöåññå ñêàíèðîâàíèÿ ïàïêè íå áûëî íàéäåíî |
íèêàêèõ êóñêîâ ôàéëà, òî cur_desc_end òàêîé æå, êàêèì áûë âíà÷àëå. |
 ýòîì ñëó÷àå ïðîöåäóðà ðàïîðòóåò î íåíàéäåííîì ôàéëå è âûõîäèò. |
18. (filefound) Ïðîïóñêàåò òåêóùóþ êîìïîíåíòó èìåíè. Åñëè îíà áûëà íå ïîñëåäíåé |
(òî åñòü ïîäïàïêîé, â êîòîðîé íóæíî ïðîèçâîäèòü äàëüíåéøèé ïîèñê), |
òî êîä ïðîâåðÿåò, ÷òî íàéäåííûé âõîä - äåéñòâèòåëüíî ïîäïàïêà, |
óñòàíàâëèâàåò íîâûé ñòàðòîâûé áëîê è âîçâðàùàåòñÿ ê ï.4. |
Åñëè æå ïîñëåäíåé, òî êîä ïðîâåðÿåò, ÷òî íàéäåííûé âõîä - ðåãóëÿðíûé |
ôàéë è íà÷èíàåò çàãðóçêó ôàéëà. |
19. Íîðìàëèçóåò óêàçàòåëü, ïî êîòîðîìó òðåáóåòñÿ ïðî÷èòàòü ôàéë. Ïîä |
íîðìàëèçàöèåé ïîíèìàåòñÿ ïðåîáðàçîâàíèå òèïà |
1234:FC08 -> (1234+0FC0):0008, êîòîðîå íå ìåíÿåò ñóììàðíîãî àäðåñà, |
íî ãàðàíòèðóåò îòñóòñòâèå ïåðåïîëíåíèé: â ïðèâåä¸ííîì ïðèìåðå ïîïûòêà |
ïåðåñëàòü 400h áàéò ïî rep movsb ïðèâåä¸ò ê òîìó, ÷òî ïîñëåäíèå 8 |
áàéò çàïèøóòñÿ íå â íóæíîå ìåñòî, à íà 64K ðàíüøå. Äàëåå íîðìàëèçàöèÿ |
áóäåò ïðîèçâîäèòüñÿ ïîñëå êàæäîé ïåðåñûëêè. Â cur_limit ïîìåùàåò |
ïðåäåëüíûé ðàçìåð äëÿ ÷òåíèÿ â áàéòàõ. |
20. (loadloop) Â öèêëå ïî íàéäåííûì ôðàãìåíòàì ôàéëà çàãðóæàåò ýòè ôðàãìåíòû |
(ïóíêòû 21-27). |
21. Îáíóëÿåò ïåðåìåííóþ [cur_start], èìåþùóþ ñìûñë ÷èñëà áàéò, êîòîðîå |
íóæíî ïðîïóñòèòü ñ íà÷àëà ôðàãìåíòà. |
22. (loadloop.loadnew) Íà ýòó ìåòêó óïðàâëåíèå ìîæåò ïîïàñòü ëèáî ñ ïðåäûäóùåãî |
øàãà, ëèáî íàïðÿìóþ èç callback-ïðîöåäóðû ïðè çàïðîñå íà ïðîäîëæåíèå |
÷òåíèÿ. Äëÿ ýòîãî è íóæíà âûøåóïîìÿíóòàÿ ïåðåìåííàÿ [cur_start] - |
ïðè ïðîäîëæåíèè ÷òåíèÿ, ïðåðâàâøåãîñÿ èç-çà êîíöà áóôåðà ïîñåðåäèíå |
ôðàãìåíòà, òàì áóäåò çàïèñàíî ñîîòâåòñòâóþùåå çíà÷åíèå. |
23. Îïðåäåëÿåò òåêóùóþ äëèíó (õðàíèòñÿ â esi) êàê ìèíèìóì èç äëèíû ôðàãìåíòà |
è ìàêñèìàëüíîé äëèíû îñòàòêà. Åñëè âòîðîå ñòðîãî ìåíüøå, òî |
çàïîìèíàåò, ÷òî ôàéë ñëèøêîì áîëüøîé è ïðî÷èòàí òîëüêî ÷àñòè÷íî. |
Îïðåäåëÿåò íîâîå çíà÷åíèå ÷èñëà ïðî÷èòàííûõ áàéò âî ôðàãìåíòå |
äëÿ âîçìîæíûõ áóäóùèõ âûçîâîâ [cur_start]. |
24. Ïåðåâîäèò ïðîïóñêàåìîå ÷èñëî áàéò â ÷èñëî ëîãè÷åñêèõ áëîêîâ è áàéò |
â ïåðâîì áëîêå, ïîñëåäíåå ÷èñëî çàïèñûâàåò â ïåðåìåííóþ [first_byte], |
îòêóäà å¸ ïîçäíåå äîñòàíåò read_many_bytes.with_first. |
25. Åñëè ôðàãìåíò çàïèñàí â îáû÷íîì ðåæèìå (non-interleaved mode), òî êîä |
îïðåäåëÿåò íà÷àëüíûé áëîê ôðàãìåíòà è âûçûâàåò âñïîìîãàòåëüíóþ ôóíêöèþ |
÷òåíèÿ áëîêîâ. Ïðè îøèáêå ÷òåíèÿ óñòàíàâëèâàåò bx=3 (êîä îøèáêè ÷òåíèÿ) |
è âûõîäèò èç öèêëà ê ï.28. |
26. Åñëè ôðàãìåíò çàïèñàí â ÷åðåäóåìîì ðåæèìå (interleaved mode), òî ñíà÷àëà |
êîä ïðîïóñêàåò íóæíîå êîëè÷åñòâî íåïðåðûâíûõ ÷àñòåé, à ïîòîì |
â öèêëå çàãðóæàåò íåïðåðûâíûå ÷àñòè ñ ïîìîùüþ òîé æå ôóíêöèè, |
â ïðîìåæóòêàõ ìåæäó ÷àñòÿìè óâåëè÷èâàÿ íîìåð íà÷àëüíîãî áëîêà. |
Ïîêà íå êîí÷èòñÿ ôðàãìåíò èëè ïîêà íå íàáåð¸òñÿ çàïðîøåííîå ÷èñëî áàéò. |
Ïðè îøèáêå ÷òåíèÿ äåëàåò òî æå ñàìîå, ÷òî è â ïðåäûäóùåì ñëó÷àå. |
27. (loadloop.loadcontinue) Åñëè ôðàãìåíòû åù¸ íå êîí÷èëèñü è ïðåäåëüíûé ðàçìåð |
åù¸ íå äîñòèãíóò, ïåðåõîäèò ê ñëåäóþùåìó ôðàãìåíòó è ï.20. Â ïðîòèâíîì |
ñëó÷àå óñòàíàâëèâàåò bx=0 ëèáî bx=1 â çàâèñèìîñòè îò òîãî, áûëî ëè |
ïåðåïîëíåíèå â ï.23. |
28. (loadloop.calclen) Ïîäñ÷èòûâàåò îáùóþ äëèíó ôàéëà, ñóììèðóÿ äëèíû âñåõ |
ôðàãìåíòîâ. |
Процедура загрузки файла (load_file): |
на входе: |
ds:di = указатель на информационную структуру, описанную в спецификации |
на загрузчик, а также в комментариях к коду |
на выходе: |
bx = статус: 0=успех, 1=файл слишком большой, прочитана только часть, |
2=файл не найден, 3=ошибка чтения |
dx:ax = размер файла, 0xFFFFFFFF, если файл не найден |
1. Если подготовительный код загрузил таблицу путей, то ищет папку в таблице, |
иначе переходит сразу к шагу 4, установив eax = начальный блок |
корневой папки. |
2. Устанавливает es:di на начало таблицы путей. Ограничение на размер |
гарантирует, что вся таблица помещается в сегменте 6000h. |
Инициализирует dx (в котором будет хранится номер текущего входа в |
таблице, считая с 1), cx (размер оставшегося участка таблицы), |
bx (номер входа, соответствующего родительской папке для текущего |
рассматриваемого участка пути). |
3. В цикле ищет вход с нужным родительским элементом и нужным именем. Элементы |
таблицы путей упорядочены (подробно о порядке написано в спецификации), |
так что если родительский элемент для очередного входа больше нужного, |
то нужного входа в таблице нет совсем, и в этом случае происходит |
выход из процедуры с bx=2, ax=dx=0xFFFF. Если обнаружился элемент, |
соответствующий очередной папке в запрошенном пути, то на рассмотрение |
выносится следующая компонента пути. Если эта компонента последняя, |
то осталось найти файл в папке, и код переходит к пункту 4, |
установив eax = начальный блок этой папки. Если же нет, то эта |
компонента должна задавать имя папки, и код возвращается к пункту 3, |
скорректировав указатель на имя ds:si и номер родительского входа bx. |
4. (parse_dir) На этом шаге заданы начальный логический блок папки в eax |
и указатель на имя файла относительно этой папки в ds:si. Если |
папку искали по таблице путей, то имя файла уже не содержит подпапок; |
если же нет, то подпапки вполне возможны. |
5. Файлы в ISO-9660 могут состоять из нескольких кусков (File Section), каждый |
из которых задаётся отдельным входом в папке. Информация обо всех |
таких кусках при просмотре папки запоминается в области, начинающейся |
с адреса 0000:2000. Переменная cur_desc_end содержит указатель на |
конец этой области, он же указатель, куда будет помещена информация |
при обнаружении следующего входа. (Папки, согласно спецификации, |
должны задаваться одним куском.) |
6. Код сначала ищет запрошенную папку в кэше папок. |
7. (parse_dir.found) Если папка уже есть в кэше, то она удаляется из списка, |
отсортированного по давности последнего обращения и код переходит к |
п.15. (Следующим действием станет добавление папки в конец списка.) |
8. (parse_dir.notfound) Если же папки нет в кэше, то её придётся загружать |
с диска. Сначала загружается первый сектор (физический сектор, |
содержащий первый логический блок). При ошибке ввода/вывода |
происходит немедленный выход из процедуры с bx=3, dx=ax=0xFFFF. |
Первый элемент папки содержит информацию о самой этой папке, конкретно |
загрузчик интересуется её размером. |
9. Если размер папки слишком большой (больше или равен 64K либо больше половины |
общего размера кэша), то кэшироваться она не будет. В этом случае код |
считывает папку посекторно во временный буфер (0000:1000) и посекторно |
сканирует на наличие запрошенного имени, пока не найдёт такого имени |
или пока не кончатся данные. (Цикл начинается со сканирования, |
поскольку первая часть данных уже прочитана.) В конце код переходит |
к п.17. |
10. (parse_dir.yescache) Если принято решение о кэшировании папки, то нужно |
обеспечить достаточное количество свободного места. Для этого может |
понадобиться выкинуть какое-то количество старых данных (цикл |
parse_dir.freeloop). Но если просто выкидывать, то, вообще говоря, |
свободное пространство окажется разорванным на несколько фрагментов. |
Поэтому при выкидывании какой-то папки из кэша загрузчик перемещает |
все следующие за ней данные назад по памяти и соответственно |
корректирует информацию о местонахождении данных в информации о кэше. |
При этом новое пространство всегда добавляется в конец доступной |
памяти. Цикл выкидывания продолжается, пока не освободится место, |
достаточное для хранения папки. Из-за ограничений на размер кэшируемых |
папок в конце концов место найдётся. |
11. Выделяется новый элемент кэша. Все удалённые на шаге 10 элементы |
организуются в единый список свободных элементов; если он непуст, |
то очередной элемент берётся из этого списка; если же пуст, то |
берётся совсем новый элемент из области памяти, предназначенной для |
элементов кэша. |
12. В новом элементе заполняются поля начального блока, сегмента с данными, |
размера в байтах. |
13. Уже прочитанные данные первого физического сектора пересылаются на |
законное место в кэше. |
14. Если все данные не исчерпываются первым сектором, то догружаются оставшиеся |
данные с диска. При ошибке чтения, как и раньше, происходит выход из |
процедуры с bx=3, ax=dx=0xFFFF. |
15. (parse_dir.scan) Новый элемент добавляется в конец списка всех элементов |
кэша. |
16. Загрузчик ищет запрошенное имя в загруженных данных папки. |
(Из-за ограничений на размер кэшируемой папки все данные располагаются |
в одном сегменте.) |
17. (parse_dir.scandone) Если в процессе сканирования папки не было найдено |
никаких кусков файла, то cur_desc_end такой же, каким был вначале. |
В этом случае процедура рапортует о ненайденном файле и выходит. |
18. (filefound) Пропускает текущую компоненту имени. Если она была не последней |
(то есть подпапкой, в которой нужно производить дальнейший поиск), |
то код проверяет, что найденный вход - действительно подпапка, |
устанавливает новый стартовый блок и возвращается к п.4. |
Если же последней, то код проверяет, что найденный вход - регулярный |
файл и начинает загрузку файла. |
19. Нормализует указатель, по которому требуется прочитать файл. Под |
нормализацией понимается преобразование типа |
1234:FC08 -> (1234+0FC0):0008, которое не меняет суммарного адреса, |
но гарантирует отсутствие переполнений: в приведённом примере попытка |
переслать 400h байт по rep movsb приведёт к тому, что последние 8 |
байт запишутся не в нужное место, а на 64K раньше. Далее нормализация |
будет производиться после каждой пересылки. В cur_limit помещает |
предельный размер для чтения в байтах. |
20. (loadloop) В цикле по найденным фрагментам файла загружает эти фрагменты |
(пункты 21-27). |
21. Обнуляет переменную [cur_start], имеющую смысл числа байт, которое |
нужно пропустить с начала фрагмента. |
22. (loadloop.loadnew) На эту метку управление может попасть либо с предыдущего |
шага, либо напрямую из callback-процедуры при запросе на продолжение |
чтения. Для этого и нужна вышеупомянутая переменная [cur_start] - |
при продолжении чтения, прервавшегося из-за конца буфера посередине |
фрагмента, там будет записано соответствующее значение. |
23. Определяет текущую длину (хранится в esi) как минимум из длины фрагмента |
и максимальной длины остатка. Если второе строго меньше, то |
запоминает, что файл слишком большой и прочитан только частично. |
Определяет новое значение числа прочитанных байт во фрагменте |
для возможных будущих вызовов [cur_start]. |
24. Переводит пропускаемое число байт в число логических блоков и байт |
в первом блоке, последнее число записывает в переменную [first_byte], |
откуда её позднее достанет read_many_bytes.with_first. |
25. Если фрагмент записан в обычном режиме (non-interleaved mode), то код |
определяет начальный блок фрагмента и вызывает вспомогательную функцию |
чтения блоков. При ошибке чтения устанавливает bx=3 (код ошибки чтения) |
и выходит из цикла к п.28. |
26. Если фрагмент записан в чередуемом режиме (interleaved mode), то сначала |
код пропускает нужное количество непрерывных частей, а потом |
в цикле загружает непрерывные части с помощью той же функции, |
в промежутках между частями увеличивая номер начального блока. |
Пока не кончится фрагмент или пока не наберётся запрошенное число байт. |
При ошибке чтения делает то же самое, что и в предыдущем случае. |
27. (loadloop.loadcontinue) Если фрагменты ещё не кончились и предельный размер |
ещё не достигнут, переходит к следующему фрагменту и п.20. В противном |
случае устанавливает bx=0 либо bx=1 в зависимости от того, было ли |
переполнение в п.23. |
28. (loadloop.calclen) Подсчитывает общую длину файла, суммируя длины всех |
фрагментов. |
Ïðîöåäóðà ïðîâåðêè, ÿâëÿåòñÿ ëè òåêóùàÿ êîìïîíåíòà èìåíè ôàéëà ïîñëåäíåé |
Процедура проверки, является ли текущая компонента имени файла последней |
(is_last_component): |
íà âõîäå: ds:si = óêàçàòåëü íà èìÿ |
íà âûõîäå: ôëàã CF óñòàíîâëåí, åñëè åñòü ïîñëåäóþùèå êîìïîíåíòû |
 öèêëå çàãðóæàåò ñèìâîëû èìåíè â ïîèñêàõ íóëåâîãî è '/'; åñëè íàø¸ëñÿ ïåðâûé, |
òî âûõîäèò (ïðè ýòîì CF=0); åñëè íàø¸ëñÿ âòîðîé, òî óñòàíàâëèâàåò CF |
è âûõîäèò. |
на входе: ds:si = указатель на имя |
на выходе: флаг CF установлен, если есть последующие компоненты |
В цикле загружает символы имени в поисках нулевого и '/'; если нашёлся первый, |
то выходит (при этом CF=0); если нашёлся второй, то устанавливает CF |
и выходит. |
Ïðîöåäóðû ïðîâåðêè íà ñîâïàäåíèå òåêóùåé êîìïîíåíòû èìåíè ôàéëà ñ èìåíåì |
òåêóùåãî ýëåìåíòà (test_filename1 äëÿ òàáëèöû ïóòåé, test_filename2 äëÿ ïàïêè): |
íà âõîäå: ds:si = óêàçàòåëü íà èìÿ, es:di = óêàçàòåëü íà ýëåìåíò |
òàáëèöû ïóòåé äëÿ test_filename1, ïàïêè äëÿ test_filename2 |
íà âûõîäå: CF óñòàíîâëåí, åñëè èìåíà íå ñîâïàäàþò |
 öèêëå ïðîâåðÿåò ñîâïàäåíèå ïðèâåä¸ííûõ ê âåðõíåìó ðåãèñòðó î÷åðåäíûõ ñèìâîëîâ |
èì¸í ôàéëà è ýëåìåíòà. Óñëîâèÿ âûõîäà èç öèêëà: çàêîí÷èëîñü èìÿ ôàéëà |
â ds:si (òî åñòü, î÷åðåäíîé ñèìâîë - íóëåâîé ëèáî '/') - ñîâïàäåíèå |
âîçìîæíî òîëüêî â ñèòóàöèè òèïà èìåíè "filename.ext" è ýëåìåíòà |
"filename.ext;1" (â ISO9660 ";1" - âåðñèÿ ôàéëà, ýëåìåíòû ñ îäèíàêîâûìè |
èìåíàìè â ïàïêå îòñîðòèðîâàíû ïî óáûâàíèþ âåðñèé); |
íåñîâïàäåíèå ñèìâîëîâ - îçíà÷àåò, ÷òî èìåíà íå ñîâïàäàþò; |
çàêîí÷èëîñü èìÿ ýëåìåíòà - íóæíî ïðîâåðèòü, çàêîí÷èëîñü ëè ïðè ýòîì èìÿ |
ôàéëà, è â çàâèñèìîñòè îò ýòîãî ïðèíèìàòü ðåøåíèå î ñîâïàäåíèè. |
Процедуры проверки на совпадение текущей компоненты имени файла с именем |
текущего элемента (test_filename1 для таблицы путей, test_filename2 для папки): |
на входе: ds:si = указатель на имя, es:di = указатель на элемент |
таблицы путей для test_filename1, папки для test_filename2 |
на выходе: CF установлен, если имена не совпадают |
В цикле проверяет совпадение приведённых к верхнему регистру очередных символов |
имён файла и элемента. Условия выхода из цикла: закончилось имя файла |
в ds:si (то есть, очередной символ - нулевой либо '/') - совпадение |
возможно только в ситуации типа имени "filename.ext" и элемента |
"filename.ext;1" (в ISO9660 ";1" - версия файла, элементы с одинаковыми |
именами в папке отсортированы по убыванию версий); |
несовпадение символов - означает, что имена не совпадают; |
закончилось имя элемента - нужно проверить, закончилось ли при этом имя |
файла, и в зависимости от этого принимать решение о совпадении. |
Ïðîöåäóðà ïðèâåäåíèÿ ñèìâîëà â âåðõíèé ðåãèñòð (toupper): |
íà âõîäå: ASCII-ñèìâîë |
íà âûõîäå: òîò æå ñèìâîë â âåðõíåì ðåãèñòðå (îí ñàì, åñëè ïîíÿòèå ðåãèñòðà ê |
íåìó íåïðèìåíèìî) |
Èç ñèìâîëîâ â äèàïàçîíå 'a' - 'z' âêëþ÷èòåëüíî âû÷èòàåò êîíñòàíòó 'a'-'A', |
îñòàëüíûå ñèìâîëû íå òðîãàåò. |
Процедура приведения символа в верхний регистр (toupper): |
на входе: ASCII-символ |
на выходе: тот же символ в верхнем регистре (он сам, если понятие регистра к |
нему неприменимо) |
Из символов в диапазоне 'a' - 'z' включительно вычитает константу 'a'-'A', |
остальные символы не трогает. |
Ïðîöåäóðà ïîèñêà ôàéëà â äàííûõ ïàïêè (scan_for_filename_in_sector): |
íà âõîäå: |
ds:si = óêàçàòåëü íà èìÿ ôàéëà |
es:bx = óêàçàòåëü íà íà÷àëî äàííûõ ïàïêè |
es:dx = óêàçàòåëü íà êîíåö äàííûõ ïàïêè |
íà âûõîäå: |
CF ñáðîøåí, åñëè íàéäåí ôèíàëüíûé ôðàãìåíò ôàéëà |
(è äàëüøå ñêàíèðîâàòü ïàïêó íå íóæíî) |
â îáëàñòü äëÿ èíôîðìàöèè î ôðàãìåíòàõ ôàéëà çàïèñûâàåòñÿ íàéäåííîå |
 öèêëå ïðîñìàòðèâàåò âñå âõîäû ïàïêè, ïðîïóñêàÿ òå, ó êîòîðûõ óñòàíîâëåí |
áèò Associated (ýòî ñïåöèàëüíûå âõîäû, äîïîëíÿþùèå îñíîâíûå). Åñëè |
èìÿ î÷åðåäíîãî âõîäà ñîâïàäàåò ñ èìåíåì ôàéëà, òî çàïîìèíàåò íîâûé |
ôðàãìåíò. Åñëè ôðàãìåíò ôèíàëüíûé (íå óñòàíîâëåí áèò Multi-Extent), |
òî êîä âûõîäèò ñ CF=0. Åñëè äîñòèãíóò êîíåö äàííûõ, òî êîä âûõîäèò |
ñ CF=1. Åñëè î÷åðåäíîé âõîä íóëåâîé (ïåðâûé áàéò íàñòîÿùåãî âõîäà |
ñîäåðæèò äëèíó è íå ìîæåò áûòü íóë¸ì), òî ïðîöåäóðà ïåðåõîäèò ê |
ðàññìîòðåíèþ ñëåäóþùåãî ëîãè÷åñêîãî áëîêà. Ïðè ýòîì ïîòåíöèàëüíî |
âîçìîæíî ïåðåïîëíåíèå ïðè äîáàâëåíèè ðàçìåðà áëîêà; ïîñêîëüêó òàêîé |
ñöåíàðèé îçíà÷àåò, ÷òî ïðîöåäóðà âûçâàíà äëÿ êýøèðîâàííîé ïàïêè |
ñ ðàçìåðîì ïî÷òè 64K è íà÷àëîì äàííûõ bx=0 (ýòî ñâîéñòâî âûçûâàþùåãî |
êîäà), à ðàçìåð áëîêà - ñòåïåíü äâîéêè, òî ïîñëå ïåðåïîëíåíèÿ âñåãäà |
bx=0, òàê ÷òî ýòî ìîæíî îáíàðóæèòü ïî âçâåä¸ííîìó ZF ïîñëå ñëîæåíèÿ; |
â ýòîì ñëó÷àå òàêæå ïðîèñõîäèò âûõîä (à ïîñëå ïåðåïîëíåíèÿ CF=1). |
Процедура поиска файла в данных папки (scan_for_filename_in_sector): |
на входе: |
ds:si = указатель на имя файла |
es:bx = указатель на начало данных папки |
es:dx = указатель на конец данных папки |
на выходе: |
CF сброшен, если найден финальный фрагмент файла |
(и дальше сканировать папку не нужно) |
в область для информации о фрагментах файла записывается найденное |
В цикле просматривает все входы папки, пропуская те, у которых установлен |
бит Associated (это специальные входы, дополняющие основные). Если |
имя очередного входа совпадает с именем файла, то запоминает новый |
фрагмент. Если фрагмент финальный (не установлен бит Multi-Extent), |
то код выходит с CF=0. Если достигнут конец данных, то код выходит |
с CF=1. Если очередной вход нулевой (первый байт настоящего входа |
содержит длину и не может быть нулём), то процедура переходит к |
рассмотрению следующего логического блока. При этом потенциально |
возможно переполнение при добавлении размера блока; поскольку такой |
сценарий означает, что процедура вызвана для кэшированной папки |
с размером почти 64K и началом данных bx=0 (это свойство вызывающего |
кода), а размер блока - степень двойки, то после переполнения всегда |
bx=0, так что это можно обнаружить по взведённому ZF после сложения; |
в этом случае также происходит выход (а после переполнения CF=1). |
Ïðîöåäóðà ïåðåâîäà ëîãè÷åñêîãî áëîêà â íîìåð ñåêòîðà: |
íà âõîäå: eax = ëîãè÷åñêèé áëîê |
íà âûõîäå: eax = ôèçè÷åñêèé ñåêòîð, dx = íîìåð ëîãè÷åñêîãî áëîêà â ñåêòîðå |
Îñóùåñòâëÿåò îáû÷íîå äåëåíèå 32-áèòíîãî ÷èñëà íà 32-áèòíîå (÷èñëî ëîãè÷åñêèõ |
áëîêîâ â ñåêòîðå, õðàíÿùååñÿ âî âíóòðåííåé ïåðåìåííîé). |
Процедура перевода логического блока в номер сектора: |
на входе: eax = логический блок |
на выходе: eax = физический сектор, dx = номер логического блока в секторе |
Осуществляет обычное деление 32-битного числа на 32-битное (число логических |
блоков в секторе, хранящееся во внутренней переменной). |
Ïðîöåäóðà çàãðóçêè ôèçè÷åñêîãî ñåêòîðà, ñîäåðæàùåãî óêàçàííûé ëîãè÷åñêèé áëîê |
Процедура загрузки физического сектора, содержащего указанный логический блок |
(load_phys_sector_for_lb_force): |
íà âõîäå: eax = ëîãè÷åñêèé áëîê; |
si - èíäèêàòîð, çàäàþùèé, ñëåäóåò ëè ÷èòàòü äàííûå â ñëó÷àå, |
åñëè ëîãè÷åñêèé áëîê íà÷èíàåòñÿ ñ íà÷àëà ôèçè÷åñêîãî: |
si = 0 - íå íóæíî, si íåíóëåâîé - íóæíî |
íà âûõîäå: |
ôèçè÷åñêèé ñåêòîð çàãðóæåí ïî àäðåñó 0000:1000 |
si óêàçûâàåò íà äàííûå ëîãè÷åñêîãî áëîêà |
CF óñòàíîâëåí ïðè îøèáêå ÷òåíèÿ |
Ïðåîáðàçóåò ïðåäûäóùåé ïðîöåäóðîé íîìåð ëîãè÷åñêîãî áëîêà â íîìåð ôèçè÷åñêîãî |
ñåêòîðà è íîìåð ëîãè÷åñêîãî áëîêà âíóòðè ñåêòîðà; åñëè ïîñëåäíÿÿ |
âåëè÷èíà íóëåâàÿ è íèêàêèõ äåéñòâèé â ýòîì ñëó÷àå íå çàïðîøåíî (si=0), |
òî íè÷åãî è íå äåëàåò; èíà÷å óñòàíàâëèâàåò si â ñîîòâåòñòâèè ñ íåé |
è ÷èòàåò ñåêòîð. |
на входе: eax = логический блок; |
si - индикатор, задающий, следует ли читать данные в случае, |
если логический блок начинается с начала физического: |
si = 0 - не нужно, si ненулевой - нужно |
на выходе: |
физический сектор загружен по адресу 0000:1000 |
si указывает на данные логического блока |
CF установлен при ошибке чтения |
Преобразует предыдущей процедурой номер логического блока в номер физического |
сектора и номер логического блока внутри сектора; если последняя |
величина нулевая и никаких действий в этом случае не запрошено (si=0), |
то ничего и не делает; иначе устанавливает si в соответствии с ней |
и читает сектор. |
Ïðîöåäóðû ÷òåíèÿ íóæíîãî ÷èñëà áàéò èç íåïðåðûâíîé öåïî÷êè ëîãè÷åñêèõ áëîêîâ |
(read_many_bytes è read_many_bytes.with_first): |
íà âõîäå: |
eax = ëîãè÷åñêèé áëîê |
esi = ÷èñëî áàéò äëÿ ÷òåíèÿ |
es:bx = óêàçàòåëü íà íà÷àëî áóôåðà, êóäà áóäóò ïðî÷èòàíû äàííûå |
cur_limit = ðàçìåð áóôåðà (íå ìåíüøå esi) |
íà âûõîäå: |
es:bx óêàçûâàåò íà êîíåö áóôåðà, â êîòîðûé áûëè ïðî÷èòàíû äàííûå |
åñëè ïðîèçîøëà îøèáêà ÷òåíèÿ, ôëàã CF óñòàíîâëåí |
cur_limit ñîîòâåòñòâóþùèì îáðàçîì óìåíüøåí |
Îòëè÷èå äâóõ ïðîöåäóð: âòîðàÿ äîïîëíèòåëüíî ïðèíèìàåò âî âíèìàíèå ïåðåìåííóþ |
[first_byte], íà÷èíàÿ ÷òåíèå ïåðâîãî áëîêà ñî ñìåùåíèÿ [first_byte]; |
ñîîòâåòñòâåííî, ïåðâàÿ ÷èòàåò áëîê ñ íà÷àëà, îáíóëÿÿ [first_byte] |
ïðè âõîäå. |
1. Îòäåëüíî ñ÷èòûâàåò ïåðâûé ôèçè÷åñêèé ñåêòîð âî âðåìåííóþ îáëàñòü 0000:1000, |
åñëè ïåðâûé ëîãè÷åñêèé áëîê íà÷èíàåòñÿ íå ñ íà÷àëà ñåêòîðà. Ïðè |
îøèáêå ÷òåíèÿ âûõîäèò èç ïðîöåäóðû. |
2. Ïåðåñûëàåò íóæíóþ ÷àñòü äàííûõ (âîçìîæíî, 0 áàéò), ïðî÷èòàííûõ â ï.1, |
â áóôåð. Íîðìàëèçóåò óêàçàòåëü íà áóôåð. |
3. Åñëè âñå íåîáõîäèìûå äàííûå óæå ïðî÷èòàíû, âûõîäèò èç ïðîöåäóðû. |
4. Äàëüíåéøèå äàííûå íàõîäÿòñÿ â íåñêîëüêèõ ôèçè÷åñêèõ ñåêòîðàõ, ïðè ýòîì, |
âîçìîæíî, ïîñëåäíèé ñåêòîð ñ÷èòûâàòü íóæíî íå öåëèêîì. |
5. Åñëè â áóôåðå åñòü ìåñòî äëÿ ñ÷èòûâàíèÿ âñåõ ñåêòîðîâ, òî ñðàçó ÷èòàþòñÿ |
âñå ñåêòîðà, ïîñëå ÷åãî óêàçàòåëü íà áóôåð íóæíûì îáðàçîì óìåíüøàåòñÿ. |
6. Åñëè æå íåò, òî ñ÷èòûâàþòñÿ âñå ñåêòîðà, êðîìå ïîñëåäíåãî, ïîñëå ÷åãî |
ïîñëåäíèé ñåêòîð ñ÷èòûâàåòñÿ îòäåëüíî âî âðåìåííóþ îáëàñòü, è óæå |
îòòóäà íóæíàÿ ÷àñòü äàííûõ êîïèðóåòñÿ â áóôåð. |
Процедуры чтения нужного числа байт из непрерывной цепочки логических блоков |
(read_many_bytes и read_many_bytes.with_first): |
на входе: |
eax = логический блок |
esi = число байт для чтения |
es:bx = указатель на начало буфера, куда будут прочитаны данные |
cur_limit = размер буфера (не меньше esi) |
на выходе: |
es:bx указывает на конец буфера, в который были прочитаны данные |
если произошла ошибка чтения, флаг CF установлен |
cur_limit соответствующим образом уменьшен |
Отличие двух процедур: вторая дополнительно принимает во внимание переменную |
[first_byte], начиная чтение первого блока со смещения [first_byte]; |
соответственно, первая читает блок с начала, обнуляя [first_byte] |
при входе. |
1. Отдельно считывает первый физический сектор во временную область 0000:1000, |
если первый логический блок начинается не с начала сектора. При |
ошибке чтения выходит из процедуры. |
2. Пересылает нужную часть данных (возможно, 0 байт), прочитанных в п.1, |
в буфер. Нормализует указатель на буфер. |
3. Если все необходимые данные уже прочитаны, выходит из процедуры. |
4. Дальнейшие данные находятся в нескольких физических секторах, при этом, |
возможно, последний сектор считывать нужно не целиком. |
5. Если в буфере есть место для считывания всех секторов, то сразу читаются |
все сектора, после чего указатель на буфер нужным образом уменьшается. |
6. Если же нет, то считываются все сектора, кроме последнего, после чего |
последний сектор считывается отдельно во временную область, и уже |
оттуда нужная часть данных копируется в буфер. |
/kernel/branches/Kolibri-acpi/bootloader/extended_primary_loader/fat1x/bootsect.txt |
---|
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. |
/kernel/branches/Kolibri-acpi/bootloader/extended_primary_loader/fat32/bootsect.txt |
---|
24,310 → 24,310 |
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
;***************************************************************************** |
×èòàé ìåæäó ñòðîê - òàì íèêîãäà íå áûâàåò îïå÷àòîê. |
Читай между строк - там никогда не бывает опечаток. |
Áóòñåêòîð äëÿ FAT32-òîìà íà íîñèòåëå ñ ðàçìåðîì ñåêòîðà 0x200 = 512 áàéò. |
Бутсектор для FAT32-тома на носителе с размером сектора 0x200 = 512 байт. |
===================================================================== |
Åñòü äâå âåðñèè â çàâèñèìîñòè îò òîãî, ïîääåðæèâàåò ëè íîñèòåëü LBA, |
âûáîð îñóùåñòâëÿåòñÿ óñòàíîâêîé êîíñòàíòû use_lba â ïåðâîé ñòðîêå èñõîäíèêà. |
Òðåáîâàíèÿ äëÿ ðàáîòû: |
1) Ñàì áóòñåêòîð, ïåðâàÿ êîïèÿ FAT è âñå èñïîëüçóåìûå ôàéëû |
äîëæíû áûòü ÷èòàáåëüíû. (Åñëè äåëî ïðîèñõîäèò íà íîñèòåëå ñ ðàçáèåíèåì íà |
ðàçäåëû è çàãðóçî÷íûé êîä â MBR äîñòàòî÷íî óìíûé, òî ÷èòàáåëüíîñòè ðåçåðâíîé |
êîïèè áóòñåêòîðà (ñåêòîð íîìåð 6 íà òîìå) äîñòàòî÷íî âìåñòî ÷èòàáåëüíîñòè |
ñàìîãî áóòñåêòîðà). |
2) Ìèíèìàëüíûé ïðîöåññîð - 80386. |
3) Â ñèñòåìå äîëæíî áûòü êàê ìèíèìóì 584K ñâîáîäíîé áàçîâîé ïàìÿòè. |
Есть две версии в зависимости от того, поддерживает ли носитель LBA, |
выбор осуществляется установкой константы use_lba в первой строке исходника. |
Требования для работы: |
1) Сам бутсектор, первая копия FAT и все используемые файлы |
должны быть читабельны. (Если дело происходит на носителе с разбиением на |
разделы и загрузочный код в MBR достаточно умный, то читабельности резервной |
копии бутсектора (сектор номер 6 на томе) достаточно вместо читабельности |
самого бутсектора). |
2) Минимальный процессор - 80386. |
3) В системе должно быть как минимум 584K свободной базовой памяти. |
===================================================================== |
Äîêóìåíòàöèÿ â òåìó (ññûëêè ïðîâåðÿëèñü íà âàëèäíîñòü 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 |
===================================================================== |
Ñõåìà èñïîëüçóåìîé ïàìÿòè: |
...-7C00 ñòåê |
7C00-7E00 êîä áóòñåêòîðà |
7E00-8200 âñïîìîãàòåëüíûé ôàéë çàãðóç÷èêà (kordldr.f32) |
8400-8C00 èíôîðìàöèÿ î êýøå äëÿ òàáëèöû FAT: 100h âõîäîâ ïî 8 |
áàéò: 4 áàéòà (äâå ññûëêè - âïåð¸ä è íàçàä) äëÿ |
îðãàíèçàöèè L2-ñïèñêà âñåõ ïðî÷èòàííûõ ñåêòîðîâ â |
ïîðÿäêå âîçðàñòàíèÿ ïîñëåäíåãî âðåìåíè èñïîëüçîâàíèÿ |
+ 4 áàéòà äëÿ íîìåðà ñåêòîðà; ïðè ïåðåïîëíåíèè êýøà |
âûêèäûâàåòñÿ ýëåìåíò èç ãîëîâû ñïèñêà, òî åñòü òîò, |
ê êîòîðîìó äîëüøå âñåõ íå áûëî îáðàùåíèé |
60000-80000 êýø äëÿ òàáëèöû FAT (100h ñåêòîðîâ) |
80000-90000 òåêóùèé êëàñòåð òåêóùåé ðàññìàòðèâàåìîé ïàïêè |
90000-... êýø äëÿ ñîäåðæèìîãî ïàïîê (êàæäîé ïàïêå îòâîäèòñÿ |
2000h áàéò = 100h âõîäîâ, îäíîâðåìåííî â êýøå |
ìîæåò íàõîäèòüñÿ íå áîëåå 8 ïàïîê; |
òî÷íûé ðàçìåð îïðåäåëÿåòñÿ ðàçìåðîì äîñòóïíîé |
ôèçè÷åñêîé ïàìÿòè - êàê ïðàâèëî, íåïîñðåäñòâåííî |
ïåðåä A0000 ðàçìåùàåòñÿ EBDA, Extended BIOS Data Area) |
Схема используемой памяти: |
...-7C00 стек |
7C00-7E00 код бутсектора |
7E00-8200 вспомогательный файл загрузчика (kordldr.f32) |
8400-8C00 информация о кэше для таблицы FAT: 100h входов по 8 |
байт: 4 байта (две ссылки - вперёд и назад) для |
организации L2-списка всех прочитанных секторов в |
порядке возрастания последнего времени использования |
+ 4 байта для номера сектора; при переполнении кэша |
выкидывается элемент из головы списка, то есть тот, |
к которому дольше всех не было обращений |
60000-80000 кэш для таблицы FAT (100h секторов) |
80000-90000 текущий кластер текущей рассматриваемой папки |
90000-... кэш для содержимого папок (каждой папке отводится |
2000h байт = 100h входов, одновременно в кэше |
может находиться не более 8 папок; |
точный размер определяется размером доступной |
физической памяти - как правило, непосредственно |
перед A0000 размещается EBDA, Extended BIOS Data Area) |
===================================================================== |
Îñíîâíîé ïðîöåññ çàãðóçêè. |
Òî÷êà âõîäà (start): ïîëó÷àåò óïðàâëåíèå îò BIOS ïðè çàãðóçêå, ïðè ýòîì |
dl ñîäåðæèò èäåíòèôèêàòîð äèñêà, ñ êîòîðîãî èä¸ò çàãðóçêà |
1. Íàñòðàèâàåò ñòåê ss:sp = 0:7C00 (ñòåê ðàñïîëàãàåòñÿ íåïîñðåäñòâåííî ïåðåä |
êîäîì), ñåãìåíò äàííûõ ds = 0, è óñòàíàâëèâàåò ss:bp íà íà÷àëî |
áóòñåêòîðà (â äàëüíåéøåì äàííûå áóäóò àäðåñîâàòüñÿ ÷åðåç [bp+N] - |
ýòî îñâîáîæäàåò ds è ýêîíîìèò íà ðàçìåðå êîäà). Ñîõðàíÿåò â ñòåêå |
èäåíòèôèêàòîð çàãðóçî÷íîãî äèñêà äëÿ ïîñëåäóþùåãî îáðàùåíèÿ |
÷åðåç byte [bp-2]. |
2. LBA-âåðñèÿ: ïðîâåðÿåò, ïîääåðæèâàåò ëè íîñèòåëü LBA, âûçîâîì ôóíêöèè 41h |
ïðåðûâàíèÿ 13h. Åñëè íåò, ïåðåõîäèò íà êîä îáðàáîòêè îøèáîê ñ |
ñîîáùåíèåì îá îòñóòñòâèè LBA. |
CHS-âåðñèÿ: îïðåäåëÿåò ãåîìåòðèþ íîñèòåëÿ âûçîâîì ôóíêöèè 8 ïðåðûâàíèÿ 13h è |
çàïèñûâàåò ïîëó÷åííûå äàííûå ïîâåðõ BPB. Åñëè âûçîâ çàâåðøèëñÿ îøèáêîé, |
ïðåäïîëàãàåò óæå ñóùåñòâóþùèå äàííûå êîððåêòíûìè. |
3. Âû÷èñëÿåò íà÷àëî äàííûõ FAT-òîìà, ñîõðàíÿåò åãî â ñòåê äëÿ ïîñëåäóþùåãî |
îáðàùåíèÿ ÷åðåç dword [bp-10].  ïðîöåññå âû÷èñëåíèÿ óçíà¸ò íà÷àëî |
ïåðâîé FAT, ñîõðàíÿåò è åãî â ñòåê äëÿ ïîñëåäóþùåãî îáðàùåíèÿ ÷åðåç |
Основной процесс загрузки. |
Точка входа (start): получает управление от BIOS при загрузке, при этом |
dl содержит идентификатор диска, с которого идёт загрузка |
1. Настраивает стек ss:sp = 0:7C00 (стек располагается непосредственно перед |
кодом), сегмент данных ds = 0, и устанавливает ss:bp на начало |
бутсектора (в дальнейшем данные будут адресоваться через [bp+N] - |
это освобождает ds и экономит на размере кода). Сохраняет в стеке |
идентификатор загрузочного диска для последующего обращения |
через byte [bp-2]. |
2. LBA-версия: проверяет, поддерживает ли носитель LBA, вызовом функции 41h |
прерывания 13h. Если нет, переходит на код обработки ошибок с |
сообщением об отсутствии LBA. |
CHS-версия: определяет геометрию носителя вызовом функции 8 прерывания 13h и |
записывает полученные данные поверх BPB. Если вызов завершился ошибкой, |
предполагает уже существующие данные корректными. |
3. Вычисляет начало данных FAT-тома, сохраняет его в стек для последующего |
обращения через dword [bp-10]. В процессе вычисления узнаёт начало |
первой FAT, сохраняет и его в стек для последующего обращения через |
dword [bp-6]. |
4. (Çàêàí÷èâàÿ òåìó ïàðàìåòðîâ â ñòåêå) Ïîìåùàåò â ñòåê dword-çíà÷åíèå -1 |
äëÿ ïîñëåäóþùåãî îáðàùåíèÿ ÷åðåç dword [bp-14] - èíèöèàëèçàöèÿ |
ïåðåìåííîé, ñîäåðæàùåé òåêóùèé ñåêòîð, íàõîäÿùèéñÿ â êýøå FAT |
(-1 íå ÿâëÿåòñÿ âàëèäíûì çíà÷åíèåì äëÿ íîìåðà ñåêòîðà FAT). |
5. Èùåò â êîðíåâîé ïàïêå ýëåìåíò kordldr.f32. Åñëè íå íàõîäèò - ïåðåõîäèò íà |
êîä îáðàáîòêè îøèáîê ñ ñîîáùåíèåì î íåíàéäåííîì çàãðóç÷èêå. |
Çàìå÷àíèå: íà ýòîì ýòàïå çàãðóçêè èñêàòü ìîæíî òîëüêî â êîðíåâîé |
ïàïêå è òîëüêî èìåíà, çàäàííûå â ôîðìàòå ôàéëîâîé ñèñòåìå FAT |
(8+3 - 8 áàéò íà èìÿ, 3 áàéòà íà ðàñøèðåíèå, âñå áóêâû äîëæíû |
áûòü çàãëàâíûìè, ïðè íåîáõîäèìîñòè èìÿ è ðàñøèðåíèå äîïîëíÿþòñÿ |
ïðîáåëàìè, ðàçäåëÿþùåé òî÷êè íåò, çàâåðøàþùåãî íóëÿ íåò). |
6. Çàãðóæàåò ïåðâûé êëàñòåð ôàéëà kordldr.f32 ïî àäðåñó 0:7E00 è ïåðåäà¸ò |
åìó óïðàâëåíèå. Ïðè ýòîì â ðåãèñòðå eax îêàçûâàåòñÿ àáñîëþòíûé |
íîìåð ïåðâîãî ñåêòîðà kordldr.f32, à â cx - ÷èñëî ñ÷èòàííûõ ñåêòîðîâ |
(ðàâíîå ðàçìåðó êëàñòåðà). |
4. (Заканчивая тему параметров в стеке) Помещает в стек dword-значение -1 |
для последующего обращения через dword [bp-14] - инициализация |
переменной, содержащей текущий сектор, находящийся в кэше FAT |
(-1 не является валидным значением для номера сектора FAT). |
5. Ищет в корневой папке элемент kordldr.f32. Если не находит - переходит на |
код обработки ошибок с сообщением о ненайденном загрузчике. |
Замечание: на этом этапе загрузки искать можно только в корневой |
папке и только имена, заданные в формате файловой системе FAT |
(8+3 - 8 байт на имя, 3 байта на расширение, все буквы должны |
быть заглавными, при необходимости имя и расширение дополняются |
пробелами, разделяющей точки нет, завершающего нуля нет). |
6. Загружает первый кластер файла kordldr.f32 по адресу 0:7E00 и передаёт |
ему управление. При этом в регистре eax оказывается абсолютный |
номер первого сектора kordldr.f32, а в 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_cluster): |
íà âõîäå äîëæíî áûòü óñòàíîâëåíî: |
Процедура чтения кластера (read_cluster): |
на входе должно быть установлено: |
ss:bp = 0:7C00 |
es:bx = óêàçàòåëü íà íà÷àëî áóôåðà, êóäà áóäóò ïðî÷èòàíû äàííûå |
eax = íîìåð êëàñòåðà |
íà âûõîäå: ecx = ÷èñëî ïðî÷èòàííûõ ñåêòîðîâ (ðàçìåð êëàñòåðà), |
es:bx óêàçûâàåò íà êîíåö áóôåðà, â êîòîðûé áûëè ïðî÷èòàíû äàííûå, |
eax è ñòàðøèå ñëîâà äðóãèõ 32-áèòíûõ ðåãèñòðîâ ðàçðóøàþòñÿ |
Çàãðóæàåò â ecx ðàçìåð êëàñòåðà, ïåðåêîäèðóåò íîìåð êëàñòåðà â íîìåð ñåêòîðà |
è ïåðåõîäèò ê ñëåäóþùåé ïðîöåäóðå. |
es:bx = указатель на начало буфера, куда будут прочитаны данные |
eax = номер кластера |
на выходе: ecx = число прочитанных секторов (размер кластера), |
es:bx указывает на конец буфера, в который были прочитаны данные, |
eax и старшие слова других 32-битных регистров разрушаются |
Загружает в ecx размер кластера, перекодирует номер кластера в номер сектора |
и переходит к следующей процедуре. |
Ïðîöåäóðà ÷òåíèÿ ñåêòîðîâ (read_sectors32 è read_sectors2): |
íà âõîäå äîëæíî áûòü óñòàíîâëåíî: |
Процедура чтения секторов (read_sectors32 и read_sectors2): |
на входе должно быть установлено: |
ss:bp = 0:7C00 |
es:bx = óêàçàòåëü íà íà÷àëî áóôåðà, êóäà áóäóò ïðî÷èòàíû äàííûå |
eax = ñòàðòîâûé ñåêòîð (îòíîñèòåëüíî íà÷àëà ëîãè÷åñêîãî äèñêà |
äëÿ read_sectors32, îòíîñèòåëüíî íà÷àëà äàííûõ |
äëÿ read_sectors2) |
cx = ÷èñëî ñåêòîðîâ (äîëæíî áûòü áîëüøå íóëÿ) |
íà âûõîäå: es:bx óêàçûâàåò íà êîíåö áóôåðà, â êîòîðûé áûëè ïðî÷èòàíû äàííûå |
ñòàðøèå ñëîâà 32-áèòíûõ ðåãèñòðîâ ìîãóò ðàçðóøèòüñÿ |
0. Åñëè âûçûâàåòñÿ read_sectors2, îíà ïåðåâîäèò óêàçàííûé åé íîìåð ñåêòîðà |
â íîìåð îòíîñèòåëüíî íà÷àëà ëîãè÷åñêîãî äèñêà, ïðèáàâëÿÿ íîìåð ñåêòîðà |
íà÷àëà äàííûõ, õðàíÿùèéñÿ â ñòåêå êàê [bp-10]. |
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 = указатель на начало буфера, куда будут прочитаны данные |
eax = стартовый сектор (относительно начала логического диска |
для read_sectors32, относительно начала данных |
для read_sectors2) |
cx = число секторов (должно быть больше нуля) |
на выходе: es:bx указывает на конец буфера, в который были прочитаны данные |
старшие слова 32-битных регистров могут разрушиться |
0. Если вызывается read_sectors2, она переводит указанный ей номер сектора |
в номер относительно начала логического диска, прибавляя номер сектора |
начала данных, хранящийся в стеке как [bp-10]. |
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. |
Ïðîöåäóðà ïîèñêà ýëåìåíòà â ïàïêå (lookup_in_dir): |
íà âõîäå äîëæíî áûòü óñòàíîâëåíî: |
Процедура поиска элемента в папке (lookup_in_dir): |
на входе должно быть установлено: |
ss:bp = 0:7C00 |
ds:si = óêàçàòåëü íà èìÿ ôàéëà â ôîðìàòå FAT (ñì. âûøå) |
eax = íà÷àëüíûé êëàñòåð ïàïêè |
ds:si = указатель на имя файла в формате FAT (см. выше) |
eax = начальный кластер папки |
bx = 0 |
íà âûõîäå: ôëàã CF îïðåäåëÿåò, óäàëîñü ëè íàéòè ôàéë; åñëè óäàëîñü, òî |
CF ñáðîøåí è es:di óêàçûâàåò íà ýëåìåíò ïàïêè |
 öèêëå ñ÷èòûâàåò êëàñòåðû ïàïêè è èùåò çàïðîøåííûé ýëåìåíò â ïðî÷èòàííûõ |
äàííûõ. Äëÿ ÷òåíèÿ êëàñòåðà èñïîëüçóåò óæå îïèñàííóþ ïðîöåäóðó read_clusters, |
äëÿ ïðîäâèæåíèÿ ïî öåïî÷êå êëàñòåðîâ - îïèñàííóþ äàëåå ïðîöåäóðó |
get_next_clusters. Äàííûå ÷èòàþòñÿ â îáëàñòü ïàìÿòè, íà÷èíàþùóþñÿ ñ àäðåñà |
8000:0000, ïðè ýòîì ïåðâûå 2000h áàéò èç äàííûõ ïàïêè (ìîæåò áûòü, ìåíüøå, |
åñëè ÷òåíèå ïðåðâ¸òñÿ ðàíüøå) íå ïåðåêðûâàþòñÿ ïîñëåäóþùèìè ÷òåíèÿìè |
(ýòî áóäåò èñïîëüçîâàíî ïîçäíåå, â ñèñòåìå êýøèðîâàíèÿ èç kordldr.f32). |
Âûõîä îñóùåñòâëÿåòñÿ â ëþáîì èç ñëåäóþùèõ ñëó÷àåâ: íàéäåí çàïðîøåííûé ýëåìåíò; |
êîí÷èëèñü ýëåìåíòû â ïàïêå (ïåðâûé áàéò î÷åðåäíîãî ýëåìåíòà íóëåâîé); |
êîí÷èëèñü äàííûå ïàïêè â ñîîòâåòñòâèè ñ öåïî÷êîé êëàñòåðîâ èç FAT. |
на выходе: флаг CF определяет, удалось ли найти файл; если удалось, то |
CF сброшен и es:di указывает на элемент папки |
В цикле считывает кластеры папки и ищет запрошенный элемент в прочитанных |
данных. Для чтения кластера использует уже описанную процедуру read_clusters, |
для продвижения по цепочке кластеров - описанную далее процедуру |
get_next_clusters. Данные читаются в область памяти, начинающуюся с адреса |
8000:0000, при этом первые 2000h байт из данных папки (может быть, меньше, |
если чтение прервётся раньше) не перекрываются последующими чтениями |
(это будет использовано позднее, в системе кэширования из kordldr.f32). |
Выход осуществляется в любом из следующих случаев: найден запрошенный элемент; |
кончились элементы в папке (первый байт очередного элемента нулевой); |
кончились данные папки в соответствии с цепочкой кластеров из FAT. |
Ïðîöåäóðà âûâîäà íà ýêðàí ASCIIZ-ñòðîêè (out_string): |
íà âõîäå: ds:si -> ñòðîêà |
 öèêëå, ïîêà íå äîñòèãíóò çàâåðøàþùèé íîëü, âûçûâàåò ôóíêöèþ int 10h/ah=0Eh. |
Процедура вывода на экран ASCIIZ-строки (out_string): |
на входе: ds:si -> строка |
В цикле, пока не достигнут завершающий ноль, вызывает функцию int 10h/ah=0Eh. |
===================================================================== |
Ðàáîòà âñïîìîãàòåëüíîãî çàãðóç÷èêà kordldr.f32: |
1. Îïðåäåëÿåò, áûë ëè îí çàãðóæåí CHS- èëè LBA-âåðñèåé áóòñåêòîðà. |
 çàâèñèìîñòè îò ýòîãî óñòàíàâëèâàåò ñìåùåíèÿ èñïîëüçóåìûõ ïðîöåäóð |
áóòñåêòîðà. Êðèòåðèé ïðîâåðêè: â CHS-âåðñèè ïî àäðåñó err íàõîäèòñÿ |
áàéò 0xE8 (ìàøèííàÿ êîìàíäà call), â LBA-âåðñèè ïî òîìó æå àäðåñó |
íàõîäèòñÿ áàéò 0x14, à àäðåñ ïðîöåäóðû err äðóãîé. |
2. Óçíà¸ò ðàçìåð ñâîáîäíîé áàçîâîé ïàìÿòè (ò.å. ñâîáîäíîãî íåïðåðûâíîãî êóñêà |
àäðåñîâ ïàìÿòè, íà÷èíàþùåãîñÿ ñ 0) âûçîâîì int 12h.  ñîîòâåòñòâèè ñ |
íèì âû÷èñëÿåò ÷èñëî ýëåìåíòîâ â êýøå ïàïîê. Õîòÿ áû äëÿ îäíîãî ýëåìåíòà |
ìåñòî äîëæíî áûòü, îòñþäà îãðàíè÷åíèå â 592 Kb (94000h áàéò). |
Çàìå÷àíèå: ýòîò ðàçìåð íå ìîæåò ïðåâîñõîäèòü 0A0000h áàéò è |
íà ïðàêòèêå îêàçûâàåòñÿ íåìíîãî (íà 1-2 êèëîáàéòà) ìåíüøèì èç-çà |
íàëè÷èÿ äîïîëíèòåëüíîé îáëàñòè äàííûõ BIOS "ââåðõó" áàçîâîé ïàìÿòè. |
3. Èíèöèàëèçèðóåò êýøèðîâàíèå ïàïîê. Áóòñåêòîð óæå çàãðóçèë êàêóþ-òî ÷àñòü |
äàííûõ êîðíåâîé ïàïêè; êîïèðóåò çàãðóæåííûå äàííûå â êýø è çàïîìèíàåò, |
÷òî â êýøå åñòü êîðíåâàÿ ïàïêà. |
4. Èíèöèàëèçèðóåò êýøèðîâàíèå FAT. Áóòñåêòîð èìååò äåëî ñ FAT â òîì è òîëüêî |
òîì ñëó÷àå, êîãäà åìó ïðèõîäèòñÿ çàãðóæàòü äàííûå êîðíåâîé ïàïêè, |
íå ïîìåñòèâøèåñÿ â îäèí êëàñòåð.  ýòîì ñëó÷àå â ïàìÿòè ïðèñóòñòâóåò |
îäèí ñåêòîð FAT (åñëè áûëî íåñêîëüêî îáðàùåíèé - ïîñëåäíèé èç |
èñïîëüçîâàííûõ). |
5. Åñëè êëàñòåð ðàâåí ñåêòîðó, òî áóòñåêòîð çàãðóçèë òîëüêî ÷àñòü ôàéëà |
kordldr.f32, è çàãðóç÷èê ïîäãðóæàåò âòîðóþ ñâîþ ÷àñòü, èñïîëüçóÿ |
çíà÷åíèÿ ðåãèñòðîâ íà âõîäå â kordldr.f32. |
6. Çàãðóæàåò âòîðè÷íûé çàãðóç÷èê kord/loader ïî àäðåñó 1000:0000. Åñëè ôàéë íå |
íàéäåí, èëè îêàçàëñÿ ïàïêîé, èëè îêàçàëñÿ ñëèøêîì áîëüøèì, òî ïåðåõîäèò |
íà êîä îáðàáîòêè îøèáîê èç áóòñåêòîðà ñ ñîîáùåíèåì |
Работа вспомогательного загрузчика kordldr.f32: |
1. Определяет, был ли он загружен CHS- или LBA-версией бутсектора. |
В зависимости от этого устанавливает смещения используемых процедур |
бутсектора. Критерий проверки: в CHS-версии по адресу err находится |
байт 0xE8 (машинная команда call), в LBA-версии по тому же адресу |
находится байт 0x14, а адрес процедуры err другой. |
2. Узнаёт размер свободной базовой памяти (т.е. свободного непрерывного куска |
адресов памяти, начинающегося с 0) вызовом int 12h. В соответствии с |
ним вычисляет число элементов в кэше папок. Хотя бы для одного элемента |
место должно быть, отсюда ограничение в 592 Kb (94000h байт). |
Замечание: этот размер не может превосходить 0A0000h байт и |
на практике оказывается немного (на 1-2 килобайта) меньшим из-за |
наличия дополнительной области данных BIOS "вверху" базовой памяти. |
3. Инициализирует кэширование папок. Бутсектор уже загрузил какую-то часть |
данных корневой папки; копирует загруженные данные в кэш и запоминает, |
что в кэше есть корневая папка. |
4. Инициализирует кэширование FAT. Бутсектор имеет дело с FAT в том и только |
том случае, когда ему приходится загружать данные корневой папки, |
не поместившиеся в один кластер. В этом случае в памяти присутствует |
один сектор FAT (если было несколько обращений - последний из |
использованных). |
5. Если кластер равен сектору, то бутсектор загрузил только часть файла |
kordldr.f32, и загрузчик подгружает вторую свою часть, используя |
значения регистров на входе в kordldr.f32. |
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 (íîìåð äèñêà). |
(Ãîâîðèòå, äèñêåòîê ñ FAT32 íå áûâàåò?  ÷¸ì-òî Âû ïðàâû... íî |
óâåðåíû ëè Âû, ÷òî íåò çàãðóçî÷íûõ óñòðîéñòâ, ïîäîáíûõ äèñêåòàì, |
íî áîëüøåãî ðàçìåðà, è äëÿ êîòîðûõ BIOS-èäåíòèôèêàòîð ìåíüøå 0x80?) |
Óñòàíàâëèâàåò bx='32' (òèï ôàéëîâîé ñèñòåìû - FAT32). |
Óñòàíàâëèâàåò si=ñìåùåíèå ôóíêöèè îáðàòíîãî âûçîâà. Ïîñêîëüêó â ýòîò |
ìîìåíò ds=0, òî ds:si îáðàçóþò ïîëíûé àäðåñ. |
9. Ïåðåäà¸ò óïðàâëåíèå ïî àäðåñó 1000:0000. |
Замечание: на этом этапе имя файла уже можно указывать вместе с путём |
и в формате ASCIIZ, хотя поддержки длинных имён и неанглийских символов |
по-прежнему нет. |
7. Изменяет код обработки ошибок бутсектора на переход на метку hooked_err. |
Это нужно, чтобы последующие обращения к коду бутсектора в случае |
ошибок чтения не выводил соответствующее сообщение с последующей |
перезагрузкой, а рапортовал об ошибке чтения, которую могло бы |
как-нибудь обработать ядро. |
8. Если загрузочный диск имеет идентификатор меньше 0x80, |
то устанавливает al='f' ("floppy"), ah=идентификатор диска, |
иначе al='h' ("hard"), ah=идентификатор диска-0x80 (номер диска). |
(Говорите, дискеток с FAT32 не бывает? В чём-то Вы правы... но |
уверены ли Вы, что нет загрузочных устройств, подобных дискетам, |
но большего размера, и для которых BIOS-идентификатор меньше 0x80?) |
Устанавливает bx='32' (тип файловой системы - FAT32). |
Устанавливает si=смещение функции обратного вызова. Поскольку в этот |
момент ds=0, то ds:si образуют полный адрес. |
9. Передаёт управление по адресу 1000:0000. |
Ôóíêöèÿ îáðàòíîãî âûçîâà äëÿ âòîðè÷íîãî çàãðóç÷èêà: |
ïðåäîñòàâëÿåò âîçìîæíîñòü ÷òåíèÿ ôàéëà. |
Âõîä è âûõîä îïèñàíû â ñïåöèôèêàöèè íà çàãðóç÷èê. |
1. Ñîõðàíÿåò ñòåê âûçûâàþùåãî êîäà è óñòàíàâëèâàåò ñâîé ñòåê: |
ss:sp = 0:(7C00-10), bp=7C00: ïàðà ss:bp ïðè ðàáîòå ñ îñòàëüíûì |
êîäîì äîëæíà óêàçûâàòü íà 0:7C00, à -10 áåð¸òñÿ îò òîãî, ÷òî |
èíèöèàëèçèðóþùèé êîä áóòñåêòîðà óæå ïîìåñòèë â ñòåê 10 áàéò ïàðàìåòðîâ, |
è îíè äîëæíû ñîõðàíÿòüñÿ â íåèçìåííîñòè. (Çíà÷åíèå [ebp-14], |
"òåêóùèé ñåêòîð, íàõîäÿùèéñÿ â êýøå FAT", íå èñïîëüçóåòñÿ ïîñëå |
èíèöèàëèçàöèè êýøèðîâàíèÿ â kordldr.f32.) |
2. Ðàçáèðàåò ïåðåäàííûå ïàðàìåòðû è âûçûâàåò íóæíóþ èç âñïîìîãàòåëüíûõ |
ïðîöåäóð (çàãðóçêè ôàéëà ëèáî ïðîäîëæåíèÿ çàãðóçêè ôàéëà). |
3. Âîññòàíàâëèâàåò ñòåê âûçûâàþùåãî êîäà è âîçâðàùàåò óïðàâëåíèå. |
Функция обратного вызова для вторичного загрузчика: |
предоставляет возможность чтения файла. |
Вход и выход описаны в спецификации на загрузчик. |
1. Сохраняет стек вызывающего кода и устанавливает свой стек: |
ss:sp = 0:(7C00-10), bp=7C00: пара ss:bp при работе с остальным |
кодом должна указывать на 0:7C00, а -10 берётся от того, что |
инициализирующий код бутсектора уже поместил в стек 10 байт параметров, |
и они должны сохраняться в неизменности. (Значение [ebp-14], |
"текущий сектор, находящийся в кэше FAT", не используется после |
инициализации кэширования в kordldr.f32.) |
2. Разбирает переданные параметры и вызывает нужную из вспомогательных |
процедур (загрузки файла либо продолжения загрузки файла). |
3. Восстанавливает стек вызывающего кода и возвращает управление. |
Âñïîìîãàòåëüíûå ïðîöåäóðû kordldr.f32. |
Ïðîöåäóðà ïîëó÷åíèÿ ñëåäóþùåãî êëàñòåðà â FAT (get_next_cluster): |
1. Âû÷èñëÿåò íîìåð ñåêòîðà â FAT, â êîòîðîì íàõîäèòñÿ çàïðîøåííûé ýëåìåíò. |
(Â ñåêòîðå 0x200 áàéò, êàæäûé âõîä çàíèìàåò 4 áàéòà.) |
2. Ïðîâåðÿåò, åñòü ëè ñåêòîð â êýøå. Åñëè åñòü, ïðîïóñêàåò øàãè 3 è 4. |
3. Åñëè íåò, òî â êýø íóæíî âñòàâèòü íîâûé ýëåìåíò. Åñëè êýø åù¸ íå çàïîëíåí, |
âûäåëÿåò î÷åðåäíîé ýëåìåíò â êîíöå êýøà. Åñëè çàïîëíåí, óäàëÿåò |
ñàìûé ñòàðûé ýëåìåíò (òîò, ê êîòîðîìó äîëüøå âñåãî íå áûëî îáðàùåíèé); |
äëÿ òîãî, ÷òîáû îòñëåæèâàòü ïîðÿäîê ýëåìåíòîâ ïî âðåìåíè ïîñëåäíåãî |
îáðàùåíèÿ, âñå (âûäåëåííûå) ýëåìåíòû êýøà ñâÿçàíû â äâóñâÿçíûé ñïèñîê, |
â êîòîðîì ïåðâûì ýëåìåíòîì ÿâëÿåòñÿ ñàìûé ñòàðûé, à ññûëêè âïåð¸ä |
óêàçûâàþò íà ñëåäóþùèé ïî âðåìåíè ïîñëåäíåãî îáðàùåíèÿ. |
4. ×èòàåò ñîîòâåòñòâóþùèé ñåêòîð FAT ñ äèñêà. |
5. Êîððåêòèðóåò ñïèñîê: òåêóùèé îáðàáàòûâàåìûé ýëåìåíò óäàëÿåòñÿ ñ òîé ïîçèöèè, |
ãäå îí íàõîäèòñÿ, è äîáàâëÿåòñÿ â êîíåö. ( ñëó÷àå ñî ñâåæåäîáàâëåííûìè |
â êýø ýëåìåíòàìè óäàëåíèÿ íå äåëàåòñÿ, ïîñêîëüêó èõ â ñïèñêå åù¸ íåò.) |
6. Ñ÷èòûâàåò íóæíûé âõîä â FAT, ñáðàñûâàÿ ñòàðøèå 4 áèòà. |
7. Ñðàâíèâàåò ïðî÷èòàííîå çíà÷åíèå ñ ïðåäåëîì: åñëè îíî ñòðîãî ìåíüøå |
0x0FFFFFF7, òî îíî çàäà¸ò íîìåð ñëåäóþùåãî êëàñòåðà â öåïî÷êå; |
â ïðîòèâíîì ñëó÷àå öåïî÷êà çàêîí÷èëàñü. |
Вспомогательные процедуры kordldr.f32. |
Процедура получения следующего кластера в FAT (get_next_cluster): |
1. Вычисляет номер сектора в FAT, в котором находится запрошенный элемент. |
(В секторе 0x200 байт, каждый вход занимает 4 байта.) |
2. Проверяет, есть ли сектор в кэше. Если есть, пропускает шаги 3 и 4. |
3. Если нет, то в кэш нужно вставить новый элемент. Если кэш ещё не заполнен, |
выделяет очередной элемент в конце кэша. Если заполнен, удаляет |
самый старый элемент (тот, к которому дольше всего не было обращений); |
для того, чтобы отслеживать порядок элементов по времени последнего |
обращения, все (выделенные) элементы кэша связаны в двусвязный список, |
в котором первым элементом является самый старый, а ссылки вперёд |
указывают на следующий по времени последнего обращения. |
4. Читает соответствующий сектор FAT с диска. |
5. Корректирует список: текущий обрабатываемый элемент удаляется с той позиции, |
где он находится, и добавляется в конец. (В случае со свежедобавленными |
в кэш элементами удаления не делается, поскольку их в списке ещё нет.) |
6. Считывает нужный вход в FAT, сбрасывая старшие 4 бита. |
7. Сравнивает прочитанное значение с пределом: если оно строго меньше |
0x0FFFFFF7, то оно задаёт номер следующего кластера в цепочке; |
в противном случае цепочка закончилась. |
Ïðîöåäóðà çàãðóçêè ôàéëà (load_file): |
1. Òåêóùàÿ ðàññìàòðèâàåìàÿ ïàïêà - êîðíåâàÿ. Â öèêëå âûïîëíÿåò øàãè 2-4. |
2. Êîíâåðòèðóåò èìÿ òåêóùåãî ðàññìàòðèâàåìîãî êîìïîíåíòà èìåíè (êîìïîíåíòû |
ðàçäåëÿþòñÿ ñèìâîëîì '/') â FAT-ôîðìàò 8+3. Åñëè ýòî íåâîçìîæíî |
(áîëüøå 8 ñèìâîëîâ â èìåíè, áîëüøå 3 ñèìâîëîâ â ðàñøèðåíèè èëè |
áîëüøå îäíîé òî÷êè), âîçâðàùàåòñÿ ñ îøèáêîé. |
3. Èùåò ýëåìåíò ñ òàêèì èìåíåì â òåêóùåé ðàññìàòðèâàåìîé ïàïêå. |
à) Ïðîâåðÿåò, åñòü ëè òàêàÿ ïàïêà â êýøå ïàïîê. (Èäåíòèôèêàöèÿ ïàïîê |
îñóùåñòâëÿåòñÿ ïî íîìåðó íà÷àëüíîãî êëàñòåðà.) Åñëè òàêîé ïàïêè åù¸ |
íåò, äîáàâëÿåò å¸ â êýø; åñëè òîò ïåðåïîëíÿåòñÿ, âûêèäûâàåò ïàïêó, |
ê êîòîðîé äîëüøå âñåãî íå áûëî îáðàùåíèé. (Äëÿ êàæäîãî ýëåìåíòà êýøà |
õðàíèòñÿ ìåòêà îò 0 äî (ðàçìåð êýøà)-1, îïðåäåëÿþùàÿ åãî íîìåð ïðè |
ñîðòèðîâêå ïî äàâíîñòè ïîñëåäíåãî îáðàùåíèÿ. Ïðè îáðàùåíèè ê êàêîìó-òî |
ýëåìåíòó åãî ìåòêà ñòàíîâèòñÿ íóëåâîé, à òå ìåòêè, êîòîðûå ìåíüøå |
ñòàðîãî çíà÷åíèÿ, óâåëè÷èâàþòñÿ íà åäèíèöó.) |
á) Ïðîñìàòðèâàåò â ïîèñêàõ çàïðîøåííîãî èìåíè âñå ýëåìåíòû èç êýøà, |
èñïîëüçóÿ ïðîöåäóðó èç áóòñåêòîðà. Åñëè îáíàðóæèâàåò èñêîìûé ýëåìåíò, |
ïåðåõîäèò ê øàãó 4. Åñëè îáíàðóæèâàåò êîíåö ïàïêè, âîçâðàùàåòñÿ èç |
ïðîöåäóðû ñ îøèáêîé. |
â)  öèêëå ñ÷èòûâàåò ïàïêó ïîñåêòîðíî. Ïðè ýòîì ïðîïóñêàåò íà÷àëüíûå |
ñåêòîðû, êîòîðûå óæå íàõîäÿòñÿ â êýøå è óæå áûëè ïðîñìîòðåíû. Êàæäûé |
ïðî÷èòàííûé ñåêòîð êîïèðóåò â êýø, åñëè òàì åù¸ îñòà¸òñÿ ìåñòî, |
è ïðîñìàòðèâàåò â í¸ì âñå ýëåìåíòû. Ðàáîòàåò, ïîêà íå ñëó÷èòñÿ îäíî èç |
òð¸õ ñîáûòèé: íàéäåí èñêîìûé ýëåìåíò; êîí÷èëèñü êëàñòåðû (ñóäÿ ïî |
öåïî÷êå êëàñòåðîâ â FAT); î÷åðåäíîé ýëåìåíò ïàïêè ñèãíàëèçèðóåò î êîíöå |
(ïåðâûé áàéò íóëåâîé).  äâóõ ïîñëåäíèõ ñëó÷àÿõ âîçâðàùàåòñÿ ñ îøèáêîé. |
4. Ïðîâåðÿåò òèï íàéäåííîãî ýëåìåíòà (ôàéë/ïàïêà): ïîñëåäíèé ýëåìåíò â |
çàïðîøåííîì èìåíè äîëæåí áûòü ôàéëîì, âñå ïðîìåæóòî÷íûå - ïàïêàìè. |
Åñëè òåêóùèé êîìïîíåíò èìåíè - ïðîìåæóòî÷íûé, ïðîäâèãàåò òåêóùóþ |
ðàññìàòðèâàåìóþ ïàïêó è âîçâðàùàåòñÿ ê ïóíêòó 2. |
5. Ïðîõîäèò ïî öåïî÷êå êëàñòåðîâ â FAT è ñ÷èòûâàåò âñå êëàñòåðû â óêàçàííûé |
ïðè âûçîâå áóôåð ïîñëåäîâàòåëüíûìè âûçîâàìè ôóíêöèè áóòñåêòîðà; |
ïðè ýòîì åñëè íåñêîëüêî êëàñòåðîâ ôàéëà ðàñïîëîæåíû íà äèñêå |
ïîñëåäîâàòåëüíî, òî èõ ÷òåíèå îáúåäèíÿåòñÿ â îäíó îïåðàöèþ. |
Ñëåäèò çà òåì, ÷òîáû íå ïðåâûñèòü óêàçàííûé ïðè âûçîâå ïðîöåäóðû |
ëèìèò ÷èñëà ñåêòîðîâ äëÿ ÷òåíèÿ. |
Процедура загрузки файла (load_file): |
1. Текущая рассматриваемая папка - корневая. В цикле выполняет шаги 2-4. |
2. Конвертирует имя текущего рассматриваемого компонента имени (компоненты |
разделяются символом '/') в FAT-формат 8+3. Если это невозможно |
(больше 8 символов в имени, больше 3 символов в расширении или |
больше одной точки), возвращается с ошибкой. |
3. Ищет элемент с таким именем в текущей рассматриваемой папке. |
а) Проверяет, есть ли такая папка в кэше папок. (Идентификация папок |
осуществляется по номеру начального кластера.) Если такой папки ещё |
нет, добавляет её в кэш; если тот переполняется, выкидывает папку, |
к которой дольше всего не было обращений. (Для каждого элемента кэша |
хранится метка от 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. |