scoutos / prex-0.9.0 / bsp / boot / x86 / tools / bootsect / bootsect.S @ 03e9c04a
History | View | Annotate | Download (9.54 KB)
1 |
/*- |
---|---|
2 |
* Copyright (c) 2005, Kohsuke Ohtani |
3 |
* All rights reserved. |
4 |
* |
5 |
* Redistribution and use in source and binary forms, with or without |
6 |
* modification, are permitted provided that the following conditions |
7 |
* are met: |
8 |
* 1. Redistributions of source code must retain the above copyright |
9 |
* notice, this list of conditions and the following disclaimer. |
10 |
* 2. Redistributions in binary form must reproduce the above copyright |
11 |
* notice, this list of conditions and the following disclaimer in the |
12 |
* documentation and/or other materials provided with the distribution. |
13 |
* 3. Neither the name of the author nor the names of any co-contributors |
14 |
* may be used to endorse or promote products derived from this software |
15 |
* without specific prior written permission. |
16 |
* |
17 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
18 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
19 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
20 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
21 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
22 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
23 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
24 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
25 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
26 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
27 |
* SUCH DAMAGE. |
28 |
*/ |
29 |
|
30 |
/** |
31 |
* bootsect.S - Boot sector for FAT |
32 |
* |
33 |
* The boot sector is 512 byte code to load the OS image. It is loaded |
34 |
* to address 0:7c00 by POST BIOS. |
35 |
* The boot sector searches the target file within the root directory of |
36 |
* FAT file system, and loads it to predefined memory address. Then, it |
37 |
* jumps to the first byte of the loaded image. |
38 |
* |
39 |
* All disk access are done by using BIOS Int13h interface. The BIOS |
40 |
* parameter block (BPB) has the disk/FAT information, and it exists |
41 |
* in the first portion of the FAT boot sector. It must be filled by the |
42 |
* FAT format utility, or the prex kernel install utility (mkboot.com). |
43 |
* This program assumes that correct BPB is stored in the boot sector. |
44 |
* |
45 |
* Limitation: |
46 |
* - Support only FAT12/16. FAT32 is not supported. |
47 |
* |
48 |
* Memory usage: |
49 |
* > 5000 - 6FFF ... Disk work area |
50 |
* > 7000 - 7BFF ... Stack |
51 |
* > 7C00 - 7DFF ... This boot sector |
52 |
* >10000 - ... FAT cache |
53 |
* >20000 - ... Data cache |
54 |
* >30000 - ... Image load address |
55 |
*/ |
56 |
.code16 |
57 |
.text |
58 |
.align 1 |
59 |
|
60 |
# Memory locations |
61 |
#define BOOT_STACK 0x7c00 |
62 |
|
63 |
#define LOAD_ADDR 0x30000 |
64 |
#define ENTRY_SEG 0x3000 |
65 |
#define ENTRY_OFF 0x0000 |
66 |
|
67 |
#define WORK_AREA 0x5000 |
68 |
#define FAT_SEG 0x1000 |
69 |
#define DATA_SEG 0x2000 |
70 |
|
71 |
#define LOAD_MAX 0xA0000 |
72 |
|
73 |
# FAT Directory entry |
74 |
#define F_NAME 0 |
75 |
#define F_ATTR 11 |
76 |
#define F_RESERVED 12 |
77 |
#define F_TIME 22 |
78 |
#define F_DATA 24 |
79 |
#define F_CLUSTER 26 |
80 |
#define F_SIZE 28 |
81 |
|
82 |
#define DIR_SIZE 32 |
83 |
#define DIRENT_PER_SECTOR 16 |
84 |
|
85 |
# BIOS parameter block (BPB) location (%bp points to 0x7c00) |
86 |
#define OEM_ID 0x03(%bp) |
87 |
#define BYTE_PER_SECTOR 0x0b(%bp) |
88 |
#define SECT_PER_CLUSTER 0x0d(%bp) |
89 |
#define RESERVED_SECTORS 0x0e(%bp) |
90 |
#define NUM_OF_FATS 0x10(%bp) |
91 |
#define ROOT_ENTRIES 0x11(%bp) |
92 |
#define TOTAL_SECTORS 0x13(%bp) |
93 |
#define MEDIA_DESCRIPTOR 0x15(%bp) |
94 |
#define SECTORS_PER_FAT 0x16(%bp) |
95 |
#define SECTORS_PER_TRACK 0x18(%bp) |
96 |
#define HEADS 0x1a(%bp) |
97 |
#define HIDDEN_SECTORS 0x1c(%bp) |
98 |
#define BIG_TOTAL_SECTORS 0x20(%bp) |
99 |
#define PHYSICAL_DRIVE 0x24(%bp) |
100 |
#define EXT_BOOT_SIGNATURE 0x26(%bp) |
101 |
#define SERIAL_NO 0x27(%bp) |
102 |
#define VOLUME_ID 0x2b(%bp) |
103 |
#define FILE_SYS_ID 0x36(%bp) |
104 |
|
105 |
#define FILE_SYS_ID_NUM 0x3a(%bp) |
106 |
|
107 |
# Local data area (Note: These data will overlap the existing code) |
108 |
#define FAT_START 0x40(%bp) |
109 |
#define DATA_START 0x44(%bp) |
110 |
|
111 |
.global _boot |
112 |
|
113 |
# |
114 |
# Boot the system |
115 |
# |
116 |
_boot: |
117 |
jmp start # Skip BPB |
118 |
nop # Nop is for DOS compatibility |
119 |
|
120 |
# |
121 |
# BPB |
122 |
# |
123 |
.ascii "PREX1.00" |
124 |
.fill 0x33, 1, 0 # Drive parameter must be |
125 |
# filled by intaller |
126 |
|
127 |
# |
128 |
# Setup stack and segment registers |
129 |
# |
130 |
start: |
131 |
cli |
132 |
cld # Clear direction flag |
133 |
xorl %eax, %eax # Set EAX to zero |
134 |
movw %ax, %ds |
135 |
movw %ax, %es |
136 |
movw %ax, %ss |
137 |
movw $(BOOT_STACK), %sp |
138 |
movw %sp, %bp # EBP = Bios Parameter Block |
139 |
sti |
140 |
|
141 |
# |
142 |
# Display boot message |
143 |
# |
144 |
movw $load_msg, %si |
145 |
movw $21, %cx |
146 |
call puts |
147 |
|
148 |
# |
149 |
# Store disk information |
150 |
# |
151 |
movl HIDDEN_SECTORS, %ebx # Get hidden sector |
152 |
movw RESERVED_SECTORS, %ax # Add reserved sector |
153 |
addl %eax, %ebx # High 16 bit of EAX is 0 |
154 |
movl %ebx, FAT_START # FAT start = hidden + reserved |
155 |
|
156 |
movzbw NUM_OF_FATS, %ax # Normally 2 |
157 |
mulw SECTORS_PER_FAT # AX = Num of sector of FATs |
158 |
addl %ebx, %eax # EAX = Start of root directory |
159 |
|
160 |
movw ROOT_ENTRIES, %bx |
161 |
shrw $4, %bx # / 16 = DIRENT_PER_SECTOR |
162 |
movw %bx, %cx # CX = Num of sectors for root directory |
163 |
|
164 |
addl %eax, %ebx # DATA start = FAT start + root |
165 |
movl %ebx, DATA_START # Start sector of data area |
166 |
|
167 |
# |
168 |
# Find the OS image in the root directory |
169 |
# |
170 |
# EAX = Start sector of root |
171 |
next_sector: |
172 |
pushw %cx |
173 |
movl $(WORK_AREA), %ebx |
174 |
pushw %bx |
175 |
call read_sector # Read 1 sector in root |
176 |
popw %di # DI = dir_entry |
177 |
movw $(DIRENT_PER_SECTOR), %cx # CX = directory count |
178 |
next_entry: |
179 |
cmpb $0, (%di) # End of dir entry ? |
180 |
je error # Not found |
181 |
testb $0x18, F_ATTR(%di) # Subdir or Volume ? |
182 |
jnz not_file # Skip it |
183 |
pusha |
184 |
movw $11, %cx # File name + ext = 11 byte |
185 |
movw $image_name, %si |
186 |
repe # Compare file name |
187 |
cmpsb |
188 |
popa |
189 |
je found_file |
190 |
not_file: |
191 |
addw $(DIR_SIZE), %di # Check next directory entry |
192 |
loop next_entry |
193 |
popw %cx |
194 |
loop next_sector |
195 |
# Fall through |
196 |
# |
197 |
# Error case |
198 |
# |
199 |
error: |
200 |
movw $err_msg, %si |
201 |
movw $5, %cx |
202 |
call puts |
203 |
hang: |
204 |
hlt |
205 |
jmp hang # Stop here |
206 |
|
207 |
# |
208 |
# Load image |
209 |
# |
210 |
found_file: |
211 |
movzwl F_CLUSTER(%di), %eax # EAX = 1st cluster of loader |
212 |
movl $(LOAD_ADDR), %ebx # EBX = 32bit load address |
213 |
load_next: |
214 |
call read_cluster # Read cluster of loader |
215 |
call next_cluster # Get next cluster# in EAX |
216 |
jb load_next # EOF ? |
217 |
|
218 |
# |
219 |
# Turn fdd motor off |
220 |
# |
221 |
movw $0x3f2, %dx |
222 |
xorb %al, %al |
223 |
outb %al, %dx |
224 |
|
225 |
# |
226 |
# Jump to loaded image |
227 |
# |
228 |
ljmp $0x3000, $0x0 |
229 |
|
230 |
# |
231 |
# Puts - Print string |
232 |
# |
233 |
# Entry: |
234 |
# SI - Pointer to message string |
235 |
# CX - Number of character |
236 |
# |
237 |
puts: |
238 |
lodsb |
239 |
movb $0x0e, %ah |
240 |
movw $0x0007, %bx |
241 |
int $0x10 |
242 |
loop puts |
243 |
ret |
244 |
|
245 |
# |
246 |
# next_cluster - Return next cluster |
247 |
# |
248 |
# Entry: |
249 |
# EAX - Current cluter# |
250 |
# |
251 |
# Exit: |
252 |
# AF - End of cluster |
253 |
# EAX - Next cluter# |
254 |
# |
255 |
# Modified: |
256 |
# Flags,CX,EDX,SI,DI |
257 |
# |
258 |
next_cluster: |
259 |
pushl %ebx |
260 |
movw %ax, %di # Save cluster# in DI |
261 |
|
262 |
movw $0xfff8, %si # Set default EOF to FAT16 |
263 |
|
264 |
movl %eax, %ecx |
265 |
shll $1, %eax # * 2 |
266 |
|
267 |
cmpb $0x36, FILE_SYS_ID_NUM # ID is 'FAT16' ? |
268 |
je fat_16 |
269 |
addl %ecx, %eax # * 3 |
270 |
shrl $1, %eax # / 2 |
271 |
movw $0xff8, %si # EOF for FAT12 |
272 |
fat_16: |
273 |
# EAX - Offset of FAT entry |
274 |
xorw %dx, %dx |
275 |
divw BYTE_PER_SECTOR |
276 |
addl FAT_START, %eax # EAX = Sector# for FAT |
277 |
# DX = Offset in sector |
278 |
movl $(WORK_AREA), %ebx |
279 |
pushw %bx |
280 |
call read_sector # Read 2 sector for border |
281 |
call read_sector # data |
282 |
popw %bx |
283 |
addw %dx, %bx |
284 |
movw (%bx), %ax |
285 |
cmpw $0xfff8, %si # FAT16 ? |
286 |
je chk_end |
287 |
|
288 |
shrw $1, %di |
289 |
jc odd_pos |
290 |
andb $0x0f, %ah |
291 |
jmp chk_end |
292 |
odd_pos: |
293 |
shrw $4, %ax |
294 |
chk_end: |
295 |
cmpw %si, %ax |
296 |
popl %ebx |
297 |
ret |
298 |
|
299 |
# |
300 |
# read_cluster - Read one cluster |
301 |
# |
302 |
# Entry: |
303 |
# EBX - 32-bit pointer to buffer |
304 |
# EAX - Cluster number |
305 |
# |
306 |
# Exit: |
307 |
# EBX - Point to next buffer |
308 |
# |
309 |
# Modified: |
310 |
# flags,ECX,ECX,EDX |
311 |
# |
312 |
read_cluster: |
313 |
pushl %eax |
314 |
decw %ax # Translate clust# to sec# |
315 |
decw %ax |
316 |
xorl %ecx, %ecx |
317 |
movb SECT_PER_CLUSTER, %cl |
318 |
mull %ecx |
319 |
addl DATA_START, %eax # EAX = Read sec# |
320 |
# CX = Read sector size |
321 |
read_loop: |
322 |
call read_sector |
323 |
cmpl $(LOAD_MAX), %ebx |
324 |
jae error |
325 |
loop read_loop |
326 |
popl %eax |
327 |
ret |
328 |
|
329 |
# |
330 |
# read_sector - Read one sector |
331 |
# |
332 |
# Entry: |
333 |
# EBX - 32-bit pointer to buffer |
334 |
# EAX - Logical sector# to read |
335 |
# |
336 |
# Exit: |
337 |
# EBX - Pointer to next buffer |
338 |
# EAX - Next sector |
339 |
# |
340 |
# Modified: |
341 |
# Flags |
342 |
# |
343 |
read_sector: |
344 |
pushal |
345 |
pushw %ds |
346 |
pushw %es |
347 |
|
348 |
movl %eax, %esi # ESI = buffer |
349 |
|
350 |
movzwl SECTORS_PER_TRACK, %ecx # Get sec/track |
351 |
xorl %edx, %edx |
352 |
divl %ecx # EAX = track# |
353 |
# DX = sec# |
354 |
movw $(DATA_SEG), %cx # Check in cache |
355 |
leaw last_data, %di |
356 |
cmpl DATA_START, %esi |
357 |
jae data_reqest |
358 |
movw $(FAT_SEG), %cx |
359 |
leaw last_fat, %di |
360 |
data_reqest: |
361 |
# CX = Cached segment |
362 |
pushal # [DI] = Cached track |
363 |
movw %cx, %es |
364 |
xorw %bx, %bx # ES:BX = Cache address |
365 |
cmpl (%di), %eax # Last track ? |
366 |
je hit_cache |
367 |
movl %eax, (%di) # Save current track# |
368 |
call read_track |
369 |
hit_cache: |
370 |
popal |
371 |
|
372 |
pushw %es |
373 |
popw %ds |
374 |
|
375 |
shlw $9, %dx # sec# * 512 |
376 |
movw %dx, %si # DS:SI = Offset in cache |
377 |
|
378 |
movw %bx, %di # [EBX] -> ES:[DI] |
379 |
andw $0xf, %di |
380 |
shrl $4, %ebx |
381 |
movw %bx, %es |
382 |
|
383 |
mov $512, %cx # Copy 1 sector |
384 |
rep |
385 |
movsb |
386 |
|
387 |
popw %es |
388 |
popw %ds |
389 |
popal |
390 |
|
391 |
addl $512, %ebx # Next buffer |
392 |
incl %eax # Next sector |
393 |
ret |
394 |
|
395 |
# |
396 |
# read_track - Read one track |
397 |
# |
398 |
# Entry: |
399 |
# ES:[BX] - Pointer to buffer |
400 |
# EAX - Track number to read |
401 |
# |
402 |
# Exit: |
403 |
# None |
404 |
# |
405 |
# Modified: |
406 |
# Flags,EAX,ECX,EDX |
407 |
# |
408 |
read_track: |
409 |
movzwl HEADS, %ecx # Get num of head |
410 |
xorl %edx, %edx |
411 |
divl %ecx # AX = cyl# |
412 |
# DL = head# |
413 |
|
414 |
movb %al, %ch # CH = cyl# (low 8 bits) |
415 |
andb $3, %ah |
416 |
shlb $6, %ah |
417 |
orb $1, %ah |
418 |
movb %ah, %cl # CL[7:6] = cyl# (high 2 bits) |
419 |
# CL[5:0] = sec# = 1 |
420 |
movb %dl, %dh # DH = Head# |
421 |
movw SECTORS_PER_TRACK, %ax # AL = Num of sectors to read |
422 |
movb $2, %ah # AH = 02h (Read Disk Sectors) |
423 |
movb PHYSICAL_DRIVE, %dl # DL = Drive# |
424 |
int $0x13 # Invoke Disk BIOS |
425 |
jc error |
426 |
ret |
427 |
|
428 |
# |
429 |
# Local Data |
430 |
# |
431 |
last_fat: .long 0xffffffff |
432 |
last_data: .long 0xffffffff |
433 |
|
434 |
load_msg: .ascii "Loading " |
435 |
image_name: .ascii "PREXOS " |
436 |
crlf: .byte 0x0a, 0x0d |
437 |
err_msg: .ascii "Error" |
438 |
|
439 |
.org 510 |
440 |
.word 0xaa55 |