Subversion Repositories Kolibri OS

Rev

Rev 1962 | 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  nor 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  ''AS IS'' AND ANY
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  BE LIABLE FOR ANY
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
 
3539 clevermous 27
						Нет повести печальнее на свете,
28
						Чем повесть о заклинившем Reset'е...
1065 Lrz 29
 
3539 clevermous 30
Загрузчик для FAT- и NTFS-томов для случаев, когда основной бутсектор загружает
31
Windows, для носителей с размером сектора 512 байт.
1065 Lrz 32
 
33
=====================================================================
34
 
3539 clevermous 35
Требования для работы:
36
1) Все используемые файлы должны быть читабельны.
37
2) Минимальный процессор - 80386.
38
3) В системе должно быть как минимум 592K свободной базовой памяти.
39
4) Пути к используемым файлам не должны содержать символических ссылок NTFS
40
	(жёсткие ссылки допускаются).
41
5) Используемые файлы не должны быть сжатыми или разреженными файлами
42
	(актуально для NTFS, для FAT выполнено автоматически).
1065 Lrz 43
 
44
=====================================================================
45
 
3539 clevermous 46
Документация в тему (ссылки проверялись на валидность 08.08.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
	спецификация NTFS: file://C:/windows/system32/drivers/ntfs.sys
51
		и file://C:/ntldr либо file://C:/bootmgr
52
	неофициальное описание NTFS: http://sourceforge.net/project/showfiles.php?group_id=13956&package_id=16543
53
	официальная спецификация расширения EDD BIOS 3.0: http://www.phoenix.com/NR/rdonlyres/19FEBD17-DB40-413C-A0B1-1F3F560E222F/0/specsedd30.pdf
54
		то же, версия 1.1: http://www.phoenix.com/NR/rdonlyres/9BEDED98-6B3F-4DAC-BBB7-FA89FA5C30F0/0/specsedd11.pdf
55
	описание функций BIOS: Interrupt List by Ralf Brown: http://www.cs.cmu.edu/~ralf/files.html
56
	официальная спецификация Boot BIOS: http://www.phoenix.com/NR/rdonlyres/56E38DE2-3E6F-4743-835F-B4A53726ABED/0/specsbbs101.pdf
57
	официальное описание bcdedit для Vista: http://www.microsoft.com/whdc/system/platform/firmware/bcdedit_reff.mspx
58
	официальное описание работы с базой данных загрузчика Vista: http://www.microsoft.com/whdc/system/platform/firmware/bcd.mspx
59
	формат таблицы разделов жёсткого диска: http://www.microsoft.com/technet/prodtechnol/windows2000serv/reskit/prork/prcb_dis_qxql.mspx
1065 Lrz 60
 
61
=====================================================================
62
 
3539 clevermous 63
Схема используемой памяти:
64
	600-2000	код загрузчика (и данные)
65
	2000-3000	стек
66
	3000-3200	сектор MBR
67
	3200-3400	бутсектор логического диска
68
	3400-3C00	информация о кэше для таблиц FAT16/FAT32:
69
			для FAT16 - массив на 0x100 байт, каждый байт равен
70
 
71
			соответствующий	сектор таблицы FAT16;
72
			для FAT32 - 100h входов по 8 байт: 4 байта
73
			(две ссылки - вперёд и назад) для организации L2-списка
74
			всех прочитанных секторов в порядке возрастания
75
			последнего времени использования + 4 байта для номера
76
			сектора; при переполнении кэша выкидывается элемент из
77
			головы списка, то есть тот, к которому дольше всех
78
			не было обращений
79
	3400-3440	информация о кэше для файловых записей NTFS в
80
			таком же формате, как и кэш для FAT32, но на 8 входов
81
	3480-34C0	заголовки для кэшей записей индекса NTFS
82
	3500-3D00	информация о кэшах записей индекса NTFS: с каждой
83
			файловой записью связан свой кэш для
84
			соответствующего индекса
85
	4000-8000	место для информации об атрибутах для NTFS
86
	60000-80000	таблица FAT12 / место под таблицу FAT16 /
87
				кэш для таблицы FAT32 / кэш для структур NTFS
88
	80000-90000	текущий рассматриваемый кластер
89
	90000-92000	FAT: кэш для корневой папки
90
	92000-...	FAT: кэш для некорневых папок (каждой папке отводится
91
			2000h байт = 100h входов, одновременно в кэше
92
			может находиться не более 7 папок;
93
			точный размер определяется размером доступной
94
			физической памяти - как правило, непосредственно
95
			перед A0000 размещается EBDA, Extended BIOS Data Area)
1065 Lrz 96
 
97
=====================================================================
98
 
3539 clevermous 99
Основной процесс загрузки.
100
0a. Загрузка из-под DOS и Win9x: установка kordldr.win осуществляется
101
	размещением команды install=c:\kordldr.win в первой строке config.sys;
102
	при этом основной загрузчик системы загружает kordldr.win как обычный
103
	com-файл, в какой-то сегмент по смещению 100h и передаёт управление
104
	в начало кода (xxxx:0100).
105
0б. Загрузка из-под WinNT/2000/XP: установка kordldr.win осуществляется
106
	добавлением строки наподобие c:\kordldr.win="KordOS" в секцию
107
	[operating systems] файла boot.ini; если загружаемый файл имеет размер
108
	не менее 8 Кб (0x2000 байт) и по смещению 3 содержит сигнатуру 'NTFS'
109
	(в случае kordldr.win так и есть), то основной загрузчик каждой из
110
	этих систем загружает kordldr.win по адресу 0D00:0000 и передаёт
111
	управление на адрес 0D00:0256.
112
0в. Загрузка из-под Vista: установка kordldr.win осуществляется манипуляциями
113
	с базой данных основного загрузчика через bcdedit и подробно описана в
114
	инструкции к kordldr.win; основной загрузчик загружает целиком
115
	kordldr.win по адресу 0000:7C00 и передаёт управление в начало кода.
116
1. При загрузке из-под DOS/9x основной загрузчик не ожидает, что загруженная
117
	им программа окажется в свою очередь загрузчиком, и в этом случае
118
	kordldr.win оказывается в условиях, когда основной загрузчик уже
119
	установил какое-то окружение, в частности, перехватил некоторые
120
	прерывания. Поэтому перед остальными действиями загрузчик должен
121
	восстановить систему в начальное состояние. (При загрузке под
122
	NT-линейкой такой проблемы не возникает, поскольку там основной
123
	загрузчик ничего в системе не трогает.) Поэтому перед собственно
124
	инициализацией KordOS при работе из-под DOS/9x производятся
125
	дополнительные действия. Первым делом kordldr проверяет, какой из
126
	случаев 0а и 0в имеет место (случай 0б отличается тем, что передаёт
127
	управление не на начало кода): определяет значение ip (команда call
128
	помещает в стек адрес следующей после call инструкции, команда pop si
129
	выталкивает его в регистр si), и если оно равно 100h, то kordldr
130
	загружен как com-файл из-под DOS/9x. Тогда он спрашивает подтверждения
131
	у пользователя (поскольку в этой схеме kordldr загружается всегда,
132
	он должен оставить возможность продолжить загрузку DOS/9x). Если
133
	пользователь хочет продолжить обычную загрузку, kordldr завершается.
134
	Иначе используется тот факт, что при выдаче прерывания перезагрузки
135
	int 19h система предварительно снимает все свои перехваты BIOSовских
136
	прерываний, а потом в свою очередь выдаёт int 19h уже BIOSу. Так что
137
	kordldr устанавливает свой обработчик трассировочного прерывания,
138
	устанавливает флаг трассировки и передаёт управление DOSовскому
139
	обработчику. Обработчик трассировочного прерывания ничего не делает
140
	до тех пор, пока следующей инструкцией не оказывается int 19h, а
141
	в этот момент отбирает управление и продолжает загрузку KordOS.
142
	При этом BIOSовские обработчики восстановлены за исключением,
143
	быть может, прерывания таймера int 8, которое, возможно, восстановлено
144
	до команды jmp far на оригинальный обработчик. В последнем случае его
145
	нужно восстановить явно.
146
2. Загрузчик перемещает свой код на адрес 0000:0600.
147
3. (метка real_entry) Загрузчик устанавливает сегментные регистры ds = es = 0,
148
	настраивает стек ss:sp = 0000:3000 и устанавливает bp так, чтобы
149
	все данные можно было адресовать через [bp+N] с однобайтовым N
150
	(в дальнейшем они так и будут адресоваться для освобождения ds и
151
	экономии на размере кода). Разрешает прерывания на случай, если
152
	они были запрещены. Выдаёт сообщение о начале загрузки, начинающееся
153
	с весёлой рожицы (символ с ASCII-кодом 2).
154
4. Определяет характеристики жёсткого диска, указанного в качестве
155
	загрузочного: проверяет поддержку LBA (функция 41h прерывания 13h),
156
	если LBA не поддерживается, то определяет геометрию - число дорожек
157
	и число секторов на дорожке (функция 8 прерывания 13h), эти параметры
158
	нужны функции чтения с диска.
159
5. (метка new_partition_ex) Устраивает цикл по разделам жёсткого диска.
160
	Цель цикла - для каждого логического диска попытаться загрузиться с
161
	него (действия по загрузке с конкретного логического диска начинаются
162
	с метки not_extended), при ошибке загрузки управление передаётся
163
	назад этому циклу (метка next_partition), и поиск подходящего раздела
164
	продолжается. На выходе заполняется одна переменная partition_start,
165
	имеющая смысл начала текущего рассматриваемого логического диска,
166
	но по ходу дела из-за приколов таблиц разделов используются ещё четыре
167
	переменных. cur_partition_ofs - фактически счётчик цикла, формально
168
	указатель на текущий вход в текущей загрузочной записи. Сама
169
	загрузочная запись считывается в память начиная с адреса 3000h.
170
	Три оставшихся нужны для правильной работы с расширенными разделами.
171
	В каждой загрузочной записи помещается не более 4 записей о разделах.
172
	Поэтому главной загрузочной записи, размещающейся в первом физическом
173
	секторе диска, может не хватить, и обычно создаётся так называемый
174
	расширенный раздел с расширенными загрузочными записями, формат
175
	которых почти идентичен главной. Расширенный раздел может быть только
176
	один, но в нём может быть много логических дисков и расширенных
177
	загрузочных записей. Расширенные загрузочные записи организованы
178
	в односвязный список, в каждой такой записи первый вход указывает
179
	на соответствующий логический диск, а второй - на следующую расширенную
180
	загрузочную запись.
181
	При этом в главной загрузочной записи все адреса разделов являются
182
	абсолютными номерами секторов. В расширенных же записях адреса разделов
183
	относительны, причём с разными базами: адрес логического диска
184
	указывается относительно расширенной записи, а адрес следующей
185
	расширенной записи указывается относительно начала расширенного
186
	раздела. Такой разнобой выглядит несколько странно, но имеет место
187
	быть. Три оставшихся переменных содержат: extended_part_start -
188
	начало расширенного раздела; extended_parent - текущая рассматриваемая
189
	расширенная загрузочная запись; extended_part_cur - следующая
190
	загрузочная запись для рассмотрения.
191
	Цикл выглядит так: просматриваются все разделы, указанные в текущей
192
	(главной или расширенной) загрузочной записи; для нормальных разделов
193
	(они же логические диски) происходит переход на not_extended, где
194
	устанавливается partition_start и начинается собственно загрузка
195
	(последующие шаги); при встрече с разделом, тип которого указывает
196
	на расширенность (5 или 0xF), код запоминает начало этого раздела
197
	(в главной загрузочной записи такой тип означает расширенный раздел,
198
	в расширенной - только указатель на следующую расширенную запись,
199
	в обоих случаях он может встретиться только один раз в данной записи);
200
	когда код доходит до конца списка, все нормальные разделы, описываемые
201
	в этой записи, уже просмотрены, так что код с чистой совестью переходит
202
	к следующей расширенной записи. Если он её не встретил, значит, уже
203
	все логические разделы были подвергнуты попыткам загрузиться, и все
204
	безрезультатно, так что выводится ругательство и работа останавливается
1065 Lrz 205
	(jmp $).
3539 clevermous 206
	Может возникнуть вопрос, зачем нужна такая сложная схема и почему
207
	нельзя узнать нужный логический диск заранее или хотя бы ограничиться
208
	первым попавшимся логическим диском, не крутя цикл. Так вот, вариант
209
	с предварительным определением нужного раздела в данном случае не
210
	используется, поскольку повлёк бы за собой нетривиальные лишние
211
	действия по установке (в текущем виде установку можно провести вручную,
212
	и она сводится к указанию системному загрузчику на существование
213
	kordldr); кстати, в альтернативной версии загрузки после
214
	Windows-загрузчика, когда установка осуществляется не вручную, а
215
	специальной программой под Windows, используется модифицированная
216
	версия, в которой как раз начальный физический сектор нужного раздела
217
	прописывается установщиком. Сам kordldr не может установить, с какого
218
	раздела его загрузил Windows-загрузчик (и вообще под NT/2000/XP обязан
219
	быть файлом на диске C:\). Вариант с первым попавшимся логическим
220
	диском был реализован в первой версии загрузчика, но по ходу дела
221
	обнаружилось, что таки нужно крутить цикл: во-вторых, может быть
222
	приятным, что сама система может стоять вовсе не на системном C:\, а и
223
	на других дисках; во-первых, диск C: может и не быть первым логическим
224
	разделом - Vista любит создавать скрытый первичный раздел перед
225
	системным, и тогда диск C: становится вторым логическим.
226
6. Извещает пользователя о том, что происходит попытка загрузки с очередного
227
	логического диска.
228
7. Читает первый сектор логического диска и определяет файловую систему.
229
	И в FAT, и в NTFS поле со смещением +11 содержит число байт в секторе
230
	и должно совпадать с характеристикой физического носителя, то есть
231
	200h байт. И в FAT, и в NTFS поле со смещением +13 содержит число
232
	секторов в кластере и должно быть степенью двойки.
233
	Критерий NTFS: поле со смещением +3 содержит строку NTFS и поле со
234
	смещением +16 нулевое (в FAT оно содержит число таблиц FAT и обязано
235
	быть ненулевым).
236
	Критерий FAT: загрузчик вычисляет число кластеров, определяет
237
	предположительный тип (FAT12/FAT16/FAT32) и проверяет байт по смещению
238
	+38 для FAT12/16, +66 для FAT32 (он должен быть равен 0x29).
239
	После определения типа файловой системы извещает пользователя об
240
	определённом типе. Если файловая система не распознана, выдаёт
241
	соответствующее сообщение и переходит к следующему логическому диску.
242
8a. Для FAT12-томов: засовывает в стек идентификатор файловой системы -
243
	константу '12'; устанавливает указатель на функцию получения следующего
244
	в цепочке FAT кластера на FAT12-обработчик; считывает в память всю
245
	таблицу FAT12 (она не превосходит 0x1800 байт = 6 Кб), при ошибке
246
	чтения пытается использовать другие копии FAT.
247
8б. Для FAT16-томов: засовывает в стек идентификатор файловой системы -
248
	константу '16'; устанавливает указатель на функцию получения следующего
249
	в цепочке FAT кластера на FAT16-обработчик; инициализирует информацию
250
	о кэше секторов FAT (массив байт с возможными значениями 0 и 1,
251
	означающими, был ли уже загружен соответствующий сектор - всего в
252
	таблице FAT16 не более 0x100 секторов) - ни один сектор ещё не
253
	загружен, все байты нулевые.
254
8в. Для FAT32-томов: засовывает в стек идентификатор файловой системы -
255
	константу '32'; устанавливает указатель на функцию получения следующего
256
	в цепочке FAT кластера на FAT16-обработчик; инициализирует информацию
257
	о кэше секторов FAT (формат информации описан выше, в распределении
258
	используемой загрузчиком памяти) - ни один сектор ещё не загружен.
259
8г. Общее для FAT-томов: определяет значения служебных переменных
260
	root_start (первый сектор корневого каталога в FAT12/16, игнорируется
261
	при обработке FAT32-томов), data_start (начало данных с поправкой,
262
	вводимой для того, чтобы кластер N начинался с сектора
263
	N*sectors_per_cluster+data_start), root_clus (первый кластер корневого
264
	каталога в FAT32, 0 в FAT12/16); устанавливает указатель на функцию
265
	загрузки файла на FAT-обработчик.
266
8д. Для NTFS-томов: засовывает в стек идентификатор файловой системы -
267
	константу 'nt'; определяет значение служебной переменной frs_size
268
	(размер в байтах файловой записи, File Record Segment), для полной
269
	корректности проверяет, что это значение (равное 0x400 байт на всех
270
	реальных NTFS-томах - единственный способ изменить его заключается
271
	в пересоздании всех системных структур вручную) не превосходит 0x1000
272
	и кратно размеру сектора 0x200 байт; инициализирует кэш файловых
273
	записей - ничего ещё не загружено; считывает первый кластер $MFT
274
	и загружает информацию о расположении на диске всей таблицы $MFT
275
	(атрибут 0x80, $Data); устанавливает указатель на функцию загрузки
276
	файла на NTFS-обработчик.
277
9. (метка load_secondary) Вызывает функцию загрузки файла для файла вторичного
278
	загрузчика. При обнаружении ошибки переходит на обработчик ошибок с
279
	соответствующим сообщением.
280
10. Устанавливает регистры для вторичного загрузчика: al='h' (жёсткий диск),
281
	ah=номер диска (для готового бинарника - 0 (BIOS-идентификатор 80h),
282
	может быть изменён путём модификации константы в исходнике или
283
	специальным установщиком), bx=идентификатор файловой системы (берётся
284
	из стека, куда ранее был засунут на шаге 8), ds:si=указатель на
285
	callback-функцию.
286
11. Передаёт управление вторичному загрузчику дальним переходом на 1000:0000.
1065 Lrz 287
 
3539 clevermous 288
Функция обратного вызова для вторичного загрузчика:
289
	предоставляет возможность чтения файла.
290
Вход и выход описаны в спецификации на загрузчик.
291
Чтение файла:
292
1. Сохраняет стек вызывающего кода и устанавливает свой стек:
293
	ss:sp = 0:3000, bp=dat: пара ss:bp при работе с остальным
294
	кодом должна указывать на 0:dat.
295
2. Разбирает переданные параметры и вызывает процедуру загрузки файла.
296
3. Восстанавливает стек вызывающего кода и возвращает управление.
1065 Lrz 297
 
3539 clevermous 298
Вспомогательные процедуры.
299
Процедура чтения секторов (read):
300
на входе должно быть установлено:
1065 Lrz 301
	ss:bp = 0:dat
3539 clevermous 302
	es:bx = указатель на начало буфера, куда будут прочитаны данные
303
	eax = стартовый сектор (относительно начала логического диска)
304
	cx = число секторов (должно быть больше нуля)
305
на выходе: es:bx указывает на конец буфера, в который были прочитаны данные,
306
	флаг CF установлен, если возникла ошибка чтения
307
1. Переводит стартовый сектор (отсчитываемый от начала тома) в сектор на
308
	устройстве, прибавляя номер первого сектора логического диска,
309
	найденный при переборе дисков.
310
2. В цикле (шаги 3-6) читает секторы, следит за тем, чтобы на каждой итерации
311
	CHS-версия: все читаемые секторы были на одной дорожке.
312
	LBA-версия: число читаемых секторов не превосходило 7Fh (требование
313
	спецификации EDD BIOS).
314
CHS-версия:
315
3. Переводит абсолютный номер сектора в CHS-систему: сектор рассчитывается как
316
	единица плюс остаток от деления абсолютного номера на число секторов
317
	на дорожке; дорожка рассчитывается как остаток от деления частного,
318
	полученного на предыдущем шаге, на число дорожек, а цилиндр - как
319
	частное от этого же деления. Если число секторов для чтения больше,
320
	чем число секторов до конца дорожки, уменьшает число секторов для
321
	чтения.
322
4. Формирует данные для вызова int 13h (ah=2 - чтение, al=число секторов,
323
	dh=головка, (младшие 6 бит cl)=сектор,
324
	(старшие 2 бита cl и весь ch)=дорожка, dl=диск, es:bx->буфер).
325
5. Вызывает BIOS. Если BIOS рапортует об ошибке, выполняет сброс диска
326
	и повторяет попытку чтения, всего делается не более трёх попыток
327
	(несколько попыток нужно в случае дискеты для гарантии того, что
328
	мотор раскрутился). Если все три раза происходит ошибка чтения,
329
	переходит на код обработки ошибок с сообщением "Read error".
330
6. В соответствии с числом прочитанных на текущей итерации секторов
331
	корректирует текущий сектор, число оставшихся секторов и указатель на
332
	буфер (в паре es:bx корректируется es). Если всё прочитано, заканчивает
333
	работу, иначе возвращается на шаг 3.
334
LBA-версия:
335
3. Если число секторов для чтения больше 7Fh, уменьшает его (для текущей
336
	итерации) до 7Fh.
337
4. Формирует в стеке пакет для int 13h (кладёт все нужные данные командами
338
	push, причём в обратном порядке: стек - структура LIFO, и данные в
339
	стеке хранятся в обратном порядке по отношению к тому, как их туда
340
	клали).
341
5. Вызывает BIOS. Если BIOS рапортует об ошибке, переходит на код обработки
342
	ошибок с сообщением "Read error". Очищает стек от пакета,
343
	сформированного на предыдущем шаге.
344
6. В соответствии с числом прочитанных на текущей итерации секторов
345
	корректирует текущий сектор, число оставшихся секторов и указатель на
346
	буфер (в паре es:bx корректируется es). Если всё прочитано, заканчивает
347
	работу, иначе возвращается на шаг 3.
1065 Lrz 348
 
3539 clevermous 349
Процедура обработки ошибок (find_error_si и find_error_sp):
350
на входе: указатель на сообщение об ошибке в si либо на верхушке стека
351
0. Если вызывается find_error_si, она помещает переданный указатель в стек.
352
1. Если ошибка произошла в процессе работы callback-функции, то
353
	(метка error_in_callback) обработчик просто возвращает управление
354
	вызвавшему коду, рапортуя о ненайденном файле.
355
2. Если же ошибка произошла до передачи управления вторичному загрузчику,
356
	обработчик выводит сообщение типа "Error: <текущий объект>: <ошибка>"
357
	и (восстановив стек) переходит к следующему логическому диску.
1065 Lrz 358
 
3539 clevermous 359
Процедура чтения файла/атрибута по известному размещению на диске
1065 Lrz 360
	(read_file_chunk):
3539 clevermous 361
на входе должно быть установлено:
362
	ds:si = указатель на информацию о размещении
363
	es:bx = указатель на начало буфера, куда будут прочитаны данные
364
	ecx = лимит числа секторов для чтения, старшее слово должно быть 0
365
на выходе: es:bx указывает на конец буфера, в который были прочитаны данные,
366
	флаг CF установлен, если возникла ошибка чтения
367
1. Определяет, является ли атрибут резидентным (возможно только в NTFS
368
	и означает, что данные файла/атрибута уже были целиком прочитаны при
369
	обработке информации о файле) или нерезидентным (означает, что данные
370
	хранятся где-то на диске, и имеется информация о том, где именно).
371
2. Для резидентных атрибутов (метка read_file_chunk.resident) просто копирует
372
	данные по месту назначения (с учётом указанного лимита).
373
3. Для нерезидентных атрибутов информация состоит из пар <размер очередного
374
	фрагмента файла в кластерах, стартовый кластер фрагмента>; процедура
375
	читает фрагменты, пока файл не закончится или пока не будет достигнут
376
	указанный лимит.
1065 Lrz 377
 
3539 clevermous 378
Процедура просмотра кэша (cache_lookup):
379
на входе должно быть установлено:
380
	eax = искомое значение
381
	ss:si = указатель на структуру-заголовок кэша
382
на выходе: ss:di = указатель на вход в кэше; флаг CF установлен, если значение
383
	было только что добавлено, и сброшен, если оно уже было в кэше.
384
1. Просматривает кэш в поисках указанного значения. Если значение найдено
385
	(при этом флаг CF оказывается сброшенным), переходит к шагу 4.
386
2. Если кэш уже заполнен, удаляет из кэша самый старый вход (он находится в
387
	голове двусвязного списка), иначе добавляет к кэшу ещё один вход.
388
3. Устанавливает в полученном входе указанное значение. Устанавливает флаг
389
	CF, последующие шаги не меняют состояния флагов. Переходит к шагу 5.
390
4. Удаляет вход из списка.
391
5. Добавляет сектор в конец списка (самый новый вход).