Subversion Repositories Kolibri OS

Rev

Rev 1942 | Go to most recent revision | Details | 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
 
27
					Встречаются вирус и FAT.
28
					- Привет, ты кто?
29
					- Я? Вирус.
30
					- A я AFT, то есть TAF, то есть FTA, черт, совсем запутался...
31
 
32
Бутсектор для FAT12/FAT16-тома на носителе с размером сектора 0x200 = 512 байт.
33
 
34
=====================================================================
35
 
36
Есть две версии в зависимости от того, поддерживает ли носитель LBA,
37
выбор осуществляется установкой константы use_lba в первой строке исходника.
38
Требования для работы:
39
1) Сам бутсектор, первая копия FAT и все используемые файлы
40
должны быть читабельны.
41
2) Минимальный процессор - 80186.
42
3) В системе должно быть как минимум 592K свободной базовой памяти.
43
 
44
=====================================================================
45
 
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
54
 
55
=====================================================================
56
 
57
Максимальное количество кластеров на FAT12-томе - 0xFF4 = 4084; каждый кластер
58
занимает 12 бит в таблице FAT, так что общий размер не превосходит
59
0x17EE = 6126 байт. Вся таблица помещается в памяти.
60
Максимальное количество кластеров на FAT16-томе - 0xFFF4 = 65524; каждый
61
кластер занимает 16 бит в таблице FAT, так что общий размер не превосходит
62
0x1FFE8 = 131048 байт. Вся таблица также помещается в памяти, однако в
63
этом случае несколько нецелесообразно считывать всю таблицу, поскольку
64
на практике нужна только небольшая её часть. Поэтому место в памяти
65
резервируется, но данные считываются только в момент, когда к ним
66
действительно идёт обращение.
67
 
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)
83
 
84
=====================================================================
85
 
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
	(равное размеру кластера).
118
 
119
Вспомогательные процедуры бутсектора.
120
Код обработки ошибок (err):
121
1. Выводит строку с сообщением об ошибке.
122
2. Выводит строку "Press any key...".
123
3. Ждёт нажатия any key.
124
4. Вызывает int 18h, давая шанс BIOSу попытаться загрузиться откуда-нибудь ещё.
125
5. Для подстраховки зацикливается.
126
 
127
Процедура чтения секторов (read_sectors и read_sectors2):
128
на входе должно быть установлено:
129
	ss:bp = 0:7C00
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.
178
 
179
Процедура поиска элемента по имени в уже прочитанных данных папки
180
	(scan_for_filename):
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
проверяет имена.
194
 
195
Процедура поиска элемента в корневой папке (lookup_in_root_dir):
196
на входе должно быть установлено:
197
	ss:bp = 0:7C00
198
	ds:si = указатель на имя файла в формате FAT (см. выше)
199
на выходе: флаг CF определяет, удалось ли найти файл; если удалось, то
200
	CF сброшен и es:di указывает на элемент папки
201
Начинает с просмотра кэшированной (начальной) части корневой папки. В цикле
202
	сканирует элементы; если по результатам сканирования обнаруживает,
203
	что нужно читать папку дальше, то считывает не более 0x10000 = 64K
204
	байт (ограничение введено по двум причинам: во-первых, чтобы заведомо
205
	не вылезти за пределы используемой памяти, во-вторых, сканирование
206
	предполагает, что все обрабатываемые элементы располагаются в одном
207
	сегменте) и продолжает цикл.
208
Сканирование прекращается в трёх случаях: обнаружен искомый элемент;
209
	кончились элементы в папке (судя по числу элементов, указанному в BPB);
210
	очередной элемент папки сигнализирует о конце (первый байт нулевой).
211
 
212
Процедура вывода на экран ASCIIZ-строки (out_string):
213
на входе: ds:si -> строка
214
В цикле, пока не достигнут завершающий ноль, вызывает функцию int 10h/ah=0Eh.
215
 
216
=====================================================================
217
 
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 не может быть корректным номером класте