Rev 1635 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1065 | Lrz | 1 | ; Copyright (c) 2008-2009, diamond |
2 | ; All rights reserved. |
||
3 | ; |
||
4 | ; Redistribution and use in source and binary forms, with or without |
||
5 | ; modification, are permitted provided that the following conditions are met: |
||
6 | ; * Redistributions of source code must retain the above copyright |
||
7 | ; notice, this list of conditions and the following disclaimer. |
||
8 | ; * Redistributions in binary form must reproduce the above copyright |
||
9 | ; notice, this list of conditions and the following disclaimer in the |
||
10 | ; documentation and/or other materials provided with the distribution. |
||
11 | ; * Neither the name of the |
||
12 | ; names of its contributors may be used to endorse or promote products |
||
13 | ; derived from this software without specific prior written permission. |
||
14 | ; |
||
15 | ; THIS SOFTWARE IS PROVIDED BY Alexey Teplov aka |
||
16 | ; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||
17 | ; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||
18 | ; DISCLAIMED. IN NO EVENT SHALL |
||
19 | ; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||
20 | ; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||
21 | ; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||
22 | ; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
23 | ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||
24 | ; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
25 | ;***************************************************************************** |
||
26 | |||
3555 | Serge | 27 | Встречаются вирус и FAT. |
28 | - Привет, ты кто? |
||
29 | - Я? Вирус. |
||
30 | - A я AFT, то есть TAF, то есть FTA, черт, совсем запутался... |
||
1065 | Lrz | 31 | |
3555 | Serge | 32 | Бутсектор для FAT12/FAT16-тома на носителе с размером сектора 0x200 = 512 байт. |
1065 | Lrz | 33 | |
34 | ===================================================================== |
||
35 | |||
3555 | Serge | 36 | Есть две версии в зависимости от того, поддерживает ли носитель LBA, |
37 | выбор осуществляется установкой константы use_lba в первой строке исходника. |
||
38 | Требования для работы: |
||
39 | 1) Сам бутсектор, первая копия FAT и все используемые файлы |
||
40 | должны быть читабельны. |
||
41 | 2) Минимальный процессор - 80186. |
||
42 | 3) В системе должно быть как минимум 592K свободной базовой памяти. |
||
1065 | Lrz | 43 | |
44 | ===================================================================== |
||
45 | |||
3555 | Serge | 46 | Документация в тему (ссылки валидны на момент написания этого файла, 15.05.2008): |
47 | официальная спецификация FAT: http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx |
||
48 | в формате PDF: http://staff.washington.edu/dittrich/misc/fatgen103.pdf |
||
49 | русский перевод: http://wasm.ru/docs/11/fatgen103-rus.zip |
||
50 | официальная спецификация расширения EDD BIOS 3.0: http://www.phoenix.com/NR/rdonlyres/19FEBD17-DB40-413C-A0B1-1F3F560E222F/0/specsedd30.pdf |
||
51 | то же, версия 1.1: http://www.phoenix.com/NR/rdonlyres/9BEDED98-6B3F-4DAC-BBB7-FA89FA5C30F0/0/specsedd11.pdf |
||
52 | описание функций BIOS: Interrupt List by Ralf Brown: http://www.cs.cmu.edu/~ralf/files.html |
||
53 | официальная спецификация Boot BIOS: http://www.phoenix.com/NR/rdonlyres/56E38DE2-3E6F-4743-835F-B4A53726ABED/0/specsbbs101.pdf |
||
1065 | Lrz | 54 | |
55 | ===================================================================== |
||
56 | |||
3555 | Serge | 57 | Максимальное количество кластеров на FAT12-томе - 0xFF4 = 4084; каждый кластер |
58 | занимает 12 бит в таблице FAT, так что общий размер не превосходит |
||
59 | 0x17EE = 6126 байт. Вся таблица помещается в памяти. |
||
60 | Максимальное количество кластеров на FAT16-томе - 0xFFF4 = 65524; каждый |
||
61 | кластер занимает 16 бит в таблице FAT, так что общий размер не превосходит |
||
62 | 0x1FFE8 = 131048 байт. Вся таблица также помещается в памяти, однако в |
||
63 | этом случае несколько нецелесообразно считывать всю таблицу, поскольку |
||
64 | на практике нужна только небольшая её часть. Поэтому место в памяти |
||
65 | резервируется, но данные считываются только в момент, когда к ним |
||
66 | действительно идёт обращение. |
||
1065 | Lrz | 67 | |
3555 | Serge | 68 | Схема используемой памяти: |
69 | ...-7C00 стек |
||
70 | 7C00-7E00 код бутсектора |
||
71 | 7E00-8200 вспомогательный файл загрузчика (kordldr.f1x) |
||
72 | 8200-8300 список загруженных секторов таблицы FAT16 |
||
73 | (1 = соответствующий сектор загружен) |
||
74 | 60000-80000 загруженная таблица FAT12 / место для таблицы FAT16 |
||
75 | 80000-90000 текущий кластер текущей рассматриваемой папки |
||
76 | 90000-92000 кэш для корневой папки |
||
77 | 92000-... кэш для некорневых папок (каждой папке отводится |
||
78 | 2000h байт = 100h входов, одновременно в кэше |
||
79 | может находиться не более 7 папок; |
||
80 | точный размер определяется размером доступной |
||
81 | физической памяти - как правило, непосредственно |
||
82 | перед A0000 размещается EBDA, Extended BIOS Data Area) |
||
1065 | Lrz | 83 | |
84 | ===================================================================== |
||
85 | |||
3555 | Serge | 86 | Основной процесс загрузки. |
87 | Точка входа (start): получает управление от BIOS при загрузке, при этом |
||
88 | dl содержит идентификатор диска, с которого идёт загрузка |
||
89 | 1. Настраивает стек ss:sp = 0:7C00 (стек располагается непосредственно перед |
||
90 | кодом), сегмент данных ds = 0, и устанавливает ss:bp на начало |
||
91 | бутсектора (в дальнейшем данные будут адресоваться через [bp+N] - |
||
92 | это освобождает ds и экономит на размере кода). |
||
93 | 2. LBA-версия: проверяет, поддерживает ли носитель LBA, вызовом функции 41h |
||
94 | прерывания 13h. Если нет, переходит на код обработки ошибок с |
||
95 | сообщением об отсутствии LBA. |
||
96 | CHS-версия: определяет геометрию носителя вызовом функции 8 прерывания 13h и |
||
97 | записывает полученные данные поверх BPB. Если вызов завершился ошибкой, |
||
98 | предполагает уже существующие данные корректными. |
||
99 | 3. Вычисляет некоторые параметры FAT-тома: начальный сектор корневой папки |
||
100 | и начальный сектор данных. Кладёт их в стек; впоследствии они |
||
101 | всегда будут лежать в стеке и адресоваться через bp. |
||
102 | 4. Считывает начало корневой папки по адресу 9000:0000. Число считываемых |
||
103 | секторов - минимум из размера корневой папки, указанного в BPB, и 16 |
||
104 | (размер кэша для корневой папки - 2000h байт = 16 секторов). |
||
105 | 5. Ищет в корневой папке элемент kordldr.f1x. Если не находит, или если |
||
106 | он оказывается папкой, или если файл имеет нулевую длину - |
||
107 | переходит на код обработки ошибок с сообщением о |
||
108 | ненайденном загрузчике. |
||
109 | Замечание: на этом этапе загрузки искать можно только в корневой |
||
110 | папке и только имена, заданные в формате файловой системе FAT |
||
111 | (8+3 - 8 байт на имя, 3 байта на расширение, все буквы должны |
||
112 | быть заглавными, при необходимости имя и расширение дополняются |
||
113 | пробелами, разделяющей точки нет, завершающего нуля нет). |
||
114 | 6. Загружает первый кластер файла kordldr.f1x по адресу 0:7E00 и передаёт |
||
115 | ему управление. При этом в регистрах dx:ax оказывается абсолютный |
||
116 | номер первого сектора kordldr.f1x, а в cx - число считанных секторов |
||
117 | (равное размеру кластера). |
||
1065 | Lrz | 118 | |
3555 | Serge | 119 | Вспомогательные процедуры бутсектора. |
120 | Код обработки ошибок (err): |
||
121 | 1. Выводит строку с сообщением об ошибке. |
||
122 | 2. Выводит строку "Press any key...". |
||
123 | 3. Ждёт нажатия any key. |
||
124 | 4. Вызывает int 18h, давая шанс BIOSу попытаться загрузиться откуда-нибудь ещё. |
||
125 | 5. Для подстраховки зацикливается. |
||
1065 | Lrz | 126 | |
3555 | Serge | 127 | Процедура чтения секторов (read_sectors и read_sectors2): |
128 | на входе должно быть установлено: |
||
1065 | Lrz | 129 | ss:bp = 0:7C00 |
3555 | Serge | 130 | es:bx = указатель на начало буфера, куда будут прочитаны данные |
131 | dx:ax = стартовый сектор (относительно начала логического диска |
||
132 | для read_sectors, относительно начала данных для read_sectors2) |
||
133 | cx = число секторов (должно быть больше нуля) |
||
134 | на выходе: es:bx указывает на конец буфера, в который были прочитаны данные |
||
135 | 0. Если вызывается read_sectors2, она переводит указанный ей номер сектора |
||
136 | в номер относительно начала логического диска, прибавляя номер сектора |
||
137 | начала данных, хранящийся в стеке как [bp-8]. |
||
138 | 1. Переводит стартовый сектор (отсчитываемый от начала тома) в сектор на |
||
139 | устройстве, прибавляя значение соответствующего поля из BPB. |
||
140 | 2. В цикле (шаги 3-6) читает секторы, следит за тем, чтобы на каждой итерации |
||
141 | CHS-версия: все читаемые секторы были на одной дорожке. |
||
142 | LBA-версия: число читаемых секторов не превосходило 7Fh (требование |
||
143 | спецификации EDD BIOS). |
||
144 | CHS-версия: |
||
145 | 3. Переводит абсолютный номер сектора в CHS-систему: сектор рассчитывается как |
||
146 | единица плюс остаток от деления абсолютного номера на число секторов |
||
147 | на дорожке; дорожка рассчитывается как остаток от деления частного, |
||
148 | полученного на предыдущем шаге, на число дорожек, а цилиндр - как |
||
149 | частное от этого же деления. Если число секторов для чтения больше, |
||
150 | чем число секторов до конца дорожки, уменьшает число секторов для |
||
151 | чтения. |
||
152 | 4. Формирует данные для вызова int 13h (ah=2 - чтение, al=число секторов, |
||
153 | dh=головка, (младшие 6 бит cl)=сектор, |
||
154 | (старшие 2 бита cl и весь ch)=дорожка, dl=диск, es:bx->буфер). |
||
155 | 5. Вызывает BIOS. Если BIOS рапортует об ошибке, выполняет сброс диска |
||
156 | и повторяет попытку чтения, всего делается не более трёх попыток |
||
157 | (несколько попыток нужно в случае дискеты для гарантии того, что |
||
158 | мотор раскрутился). Если все три раза происходит ошибка чтения, |
||
159 | переходит на код обработки ошибок с сообщением "Read error". |
||
160 | 6. В соответствии с числом прочитанных на текущей итерации секторов |
||
161 | корректирует текущий сектор, число оставшихся секторов и указатель на |
||
162 | буфер (в паре es:bx корректируется es). Если всё прочитано, заканчивает |
||
163 | работу, иначе возвращается на шаг 3. |
||
164 | LBA-версия: |
||
165 | 3. Если число секторов для чтения больше 7Fh, уменьшает его (для текущей |
||
166 | итерации) до 7Fh. |
||
167 | 4. Формирует в стеке пакет для int 13h (кладёт все нужные данные командами |
||
168 | push, причём в обратном порядке: стек - структура LIFO, и данные в |
||
169 | стеке хранятся в обратном порядке по отношению к тому, как их туда |
||
170 | клали). |
||
171 | 5. Вызывает BIOS. Если BIOS рапортует об ошибке, переходит на код обработки |
||
172 | ошибок с сообщением "Read error". Очищает стек от пакета, |
||
173 | сформированного на предыдущем шаге. |
||
174 | 6. В соответствии с числом прочитанных на текущей итерации секторов |
||
175 | корректирует текущий сектор, число оставшихся секторов и указатель на |
||
176 | буфер (в паре es:bx корректируется es). Если всё прочитано, заканчивает |
||
177 | работу, иначе возвращается на шаг 3. |
||
1065 | Lrz | 178 | |
3555 | Serge | 179 | Процедура поиска элемента по имени в уже прочитанных данных папки |
1065 | Lrz | 180 | (scan_for_filename): |
3555 | Serge | 181 | на входе должно быть установлено: |
182 | ds:si = указатель на имя файла в формате FAT (11 байт, 8 на имя, |
||
183 | 3 на расширение, все буквы заглавные, если имя/расширение |
||
184 | короче, оно дополняется до максимума пробелами) |
||
185 | es = сегмент данных папки |
||
186 | cx = число элементов в прочитанных данных |
||
187 | на выходе: ZF определяет, нужно ли продолжать разбор данных папки |
||
188 | (ZF=1, если либо найден запрошенный элемент, либо достигнут |
||
189 | конец папки); CF определяет, удалось ли найти элемент с искомым именем |
||
190 | (CF=1, если не удалось); если удалось, то es:di указывает на него. |
||
191 | scan_for_filename считает, что данные папки размещаются начиная с es:0. |
||
192 | Первой командой процедура обнуляет di. Затем просто в цикле по элементам папки |
||
193 | проверяет имена. |
||
1065 | Lrz | 194 | |
3555 | Serge | 195 | Процедура поиска элемента в корневой папке (lookup_in_root_dir): |
196 | на входе должно быть установлено: |
||
1065 | Lrz | 197 | ss:bp = 0:7C00 |
3555 | Serge | 198 | ds:si = указатель на имя файла в формате FAT (см. выше) |
199 | на выходе: флаг CF определяет, удалось ли найти файл; если удалось, то |
||
200 | CF сброшен и es:di указывает на элемент папки |
||
201 | Начинает с просмотра кэшированной (начальной) части корневой папки. В цикле |
||
202 | сканирует элементы; если по результатам сканирования обнаруживает, |
||
203 | что нужно читать папку дальше, то считывает не более 0x10000 = 64K |
||
204 | байт (ограничение введено по двум причинам: во-первых, чтобы заведомо |
||
205 | не вылезти за пределы используемой памяти, во-вторых, сканирование |
||
206 | предполагает, что все обрабатываемые элементы располагаются в одном |
||
207 | сегменте) и продолжает цикл. |
||
208 | Сканирование прекращается в трёх случаях: обнаружен искомый элемент; |
||
209 | кончились элементы в папке (судя по числу элементов, указанному в BPB); |
||
210 | очередной элемент папки сигнализирует о конце (первый байт нулевой). |
||
1065 | Lrz | 211 | |
3555 | Serge | 212 | Процедура вывода на экран ASCIIZ-строки (out_string): |
213 | на входе: ds:si -> строка |
||
214 | В цикле, пока не достигнут завершающий ноль, вызывает функцию int 10h/ah=0Eh. |
||
1065 | Lrz | 215 | |
216 | ===================================================================== |
||
217 | |||
3555 | Serge | 218 | Работа вспомогательного загрузчика kordldr.f1x: |
219 | 1. Определяет, был ли он загружен CHS- или LBA-версией бутсектора. |
||
220 | В зависимости от этого устанавливает смещения используемых процедур |
||
221 | бутсектора. Критерий проверки: scan_for_filename должна начинаться |
||
222 | с инструкции 'xor di,di' с кодом 31 FF (вообще-то эта инструкция может |
||
223 | с равным успехом ассемблироваться и как 33 FF, но fasm генерирует |
||
224 | именно такую форму). |
||
225 | 2. Узнаёт размер свободной базовой памяти (т.е. свободного непрерывного куска |
||
226 | адресов памяти, начинающегося с 0) вызовом int 12h. В соответствии с |
||
227 | ним вычисляет число элементов в кэше папок. Хотя бы для одного элемента |
||
228 | место должно быть, отсюда ограничение в 592 Kb (94000h байт). |
||
229 | Замечание: этот размер не может превосходить 0A0000h байт и |
||
230 | на практике оказывается немного (на 1-2 килобайта) меньшим из-за |
||
231 | наличия дополнительной области данных BIOS "вверху" базовой памяти. |
||
232 | 3. Определяет тип файловой системы: FAT12 или FAT16. Согласно официальной |
||
233 | спецификации от Microsoft (версия 1.03 спецификации датирована, |
||
234 | к слову, 06 декабря 2000 года), разрядность FAT определяется |
||
235 | исключительно числом кластеров: максимальное число кластеров на |
||
236 | FAT12-томе равно 4094 = 0xFF4. Согласно здравому смыслу, на FAT12 |
||
237 | может быть 0xFF5 кластеров, но не больше: кластеры нумеруются с 2, |
||
238 | а число 0xFF7 не может быть корректным номером кластера. |
||
239 | Win95/98/Me следует здравому смыслу: разграничение FAT12/16 делается |
||
240 | по максимуму 0xFF5. Драйвер FAT в WinNT/2k/XP/Vista вообще поступает |
||
241 | явно неверно, считая, что 0xFF6 (или меньше) кластеров означает |
||
242 | FAT12-том, в результате получается, что последний кластер |
||
243 | (в случае 0xFF6) неадресуем. Основной загрузчик osloader.exe |
||
244 | [встроен в ntldr] для NT/2k/XP делает так же. Первичный загрузчик |
||
245 | [бутсектор FAT12/16 загружает первый сектор ntldr, и разбор FAT-таблицы |
||
246 | лежит на нём] в NT/2k подвержен той же ошибке. В XP её таки исправили |
||
247 | в соответствии со спецификацией. Linux при определении FAT12/FAT16 |
||
248 | честно следует спецификации. |
||
249 | Здесь код основан всё же на спецификации. 9x мертва, а в линейке NT |
||
250 | Microsoft если и будет исправлять ошибки, то согласно собственному |
||
251 | описанию. |
||
252 | 4. Для FAT12: загружает в память первую копию таблицы FAT по адресу 6000:0000. |
||
253 | Если размер, указанный в BPB, превосходит 12 секторов, |
||
254 | это означает, что заявленный размер слишком большой (это не считается |
||
255 | ошибкой файловой системы), и читаются только 12 секторов (таблица FAT12 |
||
256 | заведомо влезает в такой объём данных). |
||
257 | Для FAT16: инициализирует внутренние данные, указывая, что никакой сектор |
||
258 | FAT не загружен (они будут подгружаться позднее, когда понадобятся |
||
259 | и только те, которые понадобятся). |
||
260 | 5. Если кластер равен сектору, то бутсектор загрузил только часть файла |
||
261 | kordldr.f1x, и загрузчик подгружает вторую свою часть, используя |
||
262 | значения регистров на входе в kordldr.f1x. |
||
263 | 6. Загружает вторичный загрузчик kord/loader по адресу 1000:0000. Если файл не |
||
264 | найден, или оказался папкой, или оказался слишком большим, то переходит |
||
265 | на код обработки ошибок из бутсектора с сообщением |
||
1065 | Lrz | 266 | "Fatal error: cannot load the secondary loader". |
3555 | Serge | 267 | Замечание: на этом этапе имя файла уже можно указывать вместе с путём |
268 | и в формате ASCIIZ, хотя поддержки длинных имён и неанглийских символов |
||
269 | по-прежнему нет. |
||
270 | 7. Изменяет код обработки ошибок бутсектора на переход на метку hooked_err. |
||
271 | Это нужно, чтобы последующие обращения к коду бутсектора в случае |
||
272 | ошибок чтения не выводил соответствующее сообщение с последующей |
||
273 | перезагрузкой, а рапортовал об ошибке чтения, которую мог бы |
||
274 | как-нибудь обработать вторичный загрузчик. |
||
275 | 8. Если загрузочный диск имеет идентификатор меньше 0x80, |
||
276 | то устанавливает al='f' ("floppy"), ah=идентификатор диска, |
||
277 | иначе al='h' ("hard"), ah=идентификатор диска-0x80 (номер диска). |
||
278 | Устанавливает bx='12', если тип файловой системы - FAT12, и |
||
279 | bx='16' в случае FAT16. Устанавливает si=смещение функции обратного |
||
280 | вызова. Поскольку в этот момент ds=0, то ds:si образуют полный адрес. |
||
281 | 9. Передаёт управление по адресу 1000:0000. |
||
1065 | Lrz | 282 | |
3555 | Serge | 283 | Функция обратного вызова для вторичного загрузчика: |
284 | предоставляет возможность чтения файла. |
||
285 | Вход и выход описаны в спецификации на загрузчик. |
||
286 | 1. Сохраняет стек вызывающего кода и устанавливает свой стек: |
||
287 | ss:sp = 0:(7C00-8), bp=7C00: пара ss:bp при работе с остальным |
||
288 | кодом должна указывать на 0:7C00, а -8 берётся от того, что |
||
289 | инициализирующий код бутсектора уже поместил в стек 2 двойных слова, |
||
290 | и они должны сохраняться в неизменности. |
||
291 | 2. Разбирает переданные параметры, выясняет, какое действие запрошено, |
||
292 | и вызывает нужную вспомогательную процедуру. |
||
293 | 3. Восстанавливает стек вызывающего кода и возвращает управление. |
||
1065 | Lrz | 294 | |
3555 | Serge | 295 | Вспомогательные процедуры kordldr.f1x. |
296 | Процедура получения следующего кластера в FAT (get_next_cluster): |
||
297 | 1. Вспоминает разрядность FAT, вычисленную ранее. |
||
298 | Для FAT12: |
||
299 | 2. Устанавливает ds = 0x6000 - сегмент, куда ранее была считана |
||
300 | вся таблица FAT. |
||
301 | 3. Подсчитывает si = (кластер) + (кластер)/2 - смещение в этом сегменте |
||
302 | слова, задающего следующий кластер. Загружает слово по этому адресу. |
||
303 | 4. Если кластер имеет нечётный номер, то соответствующий ему элемент |
||
304 | располагается в старших 12 битах слова, и слово нужно сдвинуть вправо |
||
305 | на 4 бита; в противном случае - в младших 12 битах, и делать ничего не |
||
306 | надо. |
||
307 | 5. Выделяет из получившегося слова 12 бит. Сравнивает их с пределом 0xFF7: |
||
308 | номера нормальных кластеров меньше, и флаг CF устанавливается; |
||
309 | специальные значения EOF и BadClus сбрасывают флаг CF. |
||
310 | Для FAT16: |
||
311 | 2. Вычисляет адрес памяти, предназначенной для соответствующего сектора данных |
||
312 | в таблице FAT. |
||
313 | 3. Если сектор ещё не загружен, то загружает его. |
||
314 | 4. Вычисляет смещение данных для конкретного кластера относительно начала |
||
315 | сектора. |
||
316 | 5. Загружает слово в ax из адреса, вычисленному на шагах 1 и 3. |
||
317 | 6. Сравнивает его с пределом 0xFFF7: номера нормальных кластеров меньше, и флаг |
||
318 | CF устанавливается; специальные значения EOF и BadClus сбрасывают CF. |
||
1065 | Lrz | 319 | |
3555 | Serge | 320 | Процедура загрузки файла (load_file): |
321 | 1. Текущая рассматриваемая папка - корневая. В цикле выполняет шаги 2-4. |
||
322 | 2. Конвертирует имя текущего рассматриваемого компонента имени (компоненты |
||
323 | разделяются символом '/') в FAT-формат 8+3. Если это невозможно |
||
324 | (больше 8 символов в имени, больше 3 символов в расширении или |
||
325 | больше одной точки), возвращается с ошибкой. |
||
326 | 3. Ищет элемент с таким именем в текущей рассматриваемой папке. Для корневой |
||
327 | папки используется процедура из бутсектора. Для остальных папок: |
||
328 | a) Проверяет, есть ли такая папка в кэше некорневых папок. |
||
329 | (Идентификация папок осуществляется по номеру начального кластера.) |
||
330 | Если такой папки ещё нет, добавляет её в кэш; если тот переполняется, |
||
331 | выкидывает папку, к которой дольше всего не было обращений. (Для |
||
332 | каждого элемента кэша хранится метка от 0 до (размер кэша)-1, |
||
333 | определяющая его номер при сортировке по давности последнего обращения. |
||
334 | При обращении к какому-то элементу его метка становится нулевой, |
||
335 | а те метки, которые меньше старого значения, увеличиваются на единицу.) |
||
336 | б) Просматривает в поисках запрошенного имени все элементы из кэша, |
||
337 | используя процедуру из бутсектора. Если обнаруживает искомый элемент, |
||
338 | переходит к шагу 4. Если обнаруживает конец папки, возвращается из |
||
339 | процедуры с ошибкой. |
||
340 | в) В цикле считывает папку посекторно. При этом пропускает начальные |
||
341 | секторы, которые уже находятся в кэше и уже были просмотрены. Каждый |
||
342 | прочитанный сектор копирует в кэш, если там ещё остаётся место, |
||
343 | и просматривает в нём все элементы. Работает, пока не случится одно из |
||
344 | трёх событий: найден искомый элемент; кончились кластеры (судя по |
||
345 | цепочке кластеров в FAT); очередной элемент папки сигнализирует о конце |
||
346 | (первый байт нулевой). В двух последних случаях возвращается с ошибкой. |
||
347 | 4. Проверяет тип найденного элемента (файл/папка): последний элемент в |
||
348 | запрошенном имени должен быть файлом, все промежуточные - папками. |
||
349 | Если текущий компонент имени - промежуточный, продвигает текущую |
||
350 | рассматриваемую папку и возвращается к пункту 2. |
||
351 | 5. Проходит по цепочке кластеров в FAT и считывает все кластеры в указанный |
||
352 | при вызове буфер последовательными вызовами функции бутсектора; |
||
353 | при этом если несколько кластеров файла расположены на диске |
||
354 | последовательно, то их чтение объединяется в одну операцию. |
||
355 | Следит за тем, чтобы не превысить указанный при вызове процедуры |
||
356 | лимит числа секторов для чтения. |
||
1065 | Lrz | 357 | |
3555 | Serge | 358 | Процедура продолжения загрузки файла (continue_load_file): встроена |
359 | внутрь шага 5 load_file; загружает в регистры нужные значения (ранее |
||
360 | сохранённые из load_file) и продолжает шаг 5. |