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. Если же нет, то считываются все сектора, кроме последнего, после чего |
последний сектор считывается отдельно во временную область, и уже |
оттуда нужная часть данных копируется в буфер. |