Contents of /trunk/mkinitrd-magellan/isolinux/isolinux.asm
Parent Directory | Revision Log
Revision 532 -
(show annotations)
(download)
Sat Sep 1 22:45:15 2007 UTC (17 years ago) by niro
File size: 41054 byte(s)
Sat Sep 1 22:45:15 2007 UTC (17 years ago) by niro
File size: 41054 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd
1 | ; -*- fundamental -*- (asm-mode sucks) |
2 | ; $Id: isolinux.asm,v 1.1 2007-09-01 22:44:04 niro Exp $ |
3 | ; **************************************************************************** |
4 | ; |
5 | ; isolinux.asm |
6 | ; |
7 | ; A program to boot Linux kernels off a CD-ROM using the El Torito |
8 | ; boot standard in "no emulation" mode, making the entire filesystem |
9 | ; available. It is based on the SYSLINUX boot loader for MS-DOS |
10 | ; floppies. |
11 | ; |
12 | ; Copyright (C) 1994-2005 H. Peter Anvin |
13 | ; |
14 | ; This program is free software; you can redistribute it and/or modify |
15 | ; it under the terms of the GNU General Public License as published by |
16 | ; the Free Software Foundation, Inc., 53 Temple Place Ste 330, |
17 | ; Boston MA 02111-1307, USA; either version 2 of the License, or |
18 | ; (at your option) any later version; incorporated herein by reference. |
19 | ; |
20 | ; **************************************************************************** |
21 | |
22 | %define IS_ISOLINUX 1 |
23 | %include "macros.inc" |
24 | %include "config.inc" |
25 | %include "kernel.inc" |
26 | %include "bios.inc" |
27 | %include "tracers.inc" |
28 | %include "layout.inc" |
29 | |
30 | ; |
31 | ; Some semi-configurable constants... change on your own risk. |
32 | ; |
33 | my_id equ isolinux_id |
34 | FILENAME_MAX_LG2 equ 8 ; log2(Max filename size Including final null) |
35 | FILENAME_MAX equ (1 << FILENAME_MAX_LG2) |
36 | NULLFILE equ 0 ; Zero byte == null file name |
37 | NULLOFFSET equ 0 ; Position in which to look |
38 | retry_count equ 6 ; How patient are we with the BIOS? |
39 | %assign HIGHMEM_SLOP 128*1024 ; Avoid this much memory near the top |
40 | MAX_OPEN_LG2 equ 6 ; log2(Max number of open files) |
41 | MAX_OPEN equ (1 << MAX_OPEN_LG2) |
42 | SECTOR_SHIFT equ 11 ; 2048 bytes/sector (El Torito requirement) |
43 | SECTOR_SIZE equ (1 << SECTOR_SHIFT) |
44 | |
45 | ; |
46 | ; This is what we need to do when idle |
47 | ; |
48 | %macro RESET_IDLE 0 |
49 | ; Nothing |
50 | %endmacro |
51 | %macro DO_IDLE 0 |
52 | ; Nothing |
53 | %endmacro |
54 | |
55 | ; |
56 | ; The following structure is used for "virtual kernels"; i.e. LILO-style |
57 | ; option labels. The options we permit here are `kernel' and `append |
58 | ; Since there is no room in the bottom 64K for all of these, we |
59 | ; stick them at vk_seg:0000 and copy them down before we need them. |
60 | ; |
61 | struc vkernel |
62 | vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!** |
63 | vk_rname: resb FILENAME_MAX ; Real name |
64 | vk_appendlen: resw 1 |
65 | alignb 4 |
66 | vk_append: resb max_cmd_len+1 ; Command line |
67 | alignb 4 |
68 | vk_end: equ $ ; Should be <= vk_size |
69 | endstruc |
70 | |
71 | ; |
72 | ; Segment assignments in the bottom 640K |
73 | ; 0000h - main code/data segment (and BIOS segment) |
74 | ; |
75 | real_mode_seg equ 3000h |
76 | vk_seg equ 2000h ; Virtual kernels |
77 | xfer_buf_seg equ 1000h ; Bounce buffer for I/O to high mem |
78 | comboot_seg equ real_mode_seg ; COMBOOT image loading zone |
79 | |
80 | ; |
81 | ; File structure. This holds the information for each currently open file. |
82 | ; |
83 | struc open_file_t |
84 | file_sector resd 1 ; Sector pointer (0 = structure free) |
85 | file_left resd 1 ; Number of sectors left |
86 | endstruc |
87 | |
88 | %ifndef DEPEND |
89 | %if (open_file_t_size & (open_file_t_size-1)) |
90 | %error "open_file_t is not a power of 2" |
91 | %endif |
92 | %endif |
93 | |
94 | struc dir_t |
95 | dir_lba resd 1 ; Directory start (LBA) |
96 | dir_len resd 1 ; Length in bytes |
97 | dir_clust resd 1 ; Length in clusters |
98 | endstruc |
99 | |
100 | ; --------------------------------------------------------------------------- |
101 | ; BEGIN CODE |
102 | ; --------------------------------------------------------------------------- |
103 | |
104 | ; |
105 | ; Memory below this point is reserved for the BIOS and the MBR |
106 | ; |
107 | section .earlybss |
108 | trackbufsize equ 8192 |
109 | trackbuf resb trackbufsize ; Track buffer goes here |
110 | getcbuf resb trackbufsize |
111 | ; ends at 4800h |
112 | |
113 | section .bss |
114 | alignb 4 |
115 | ISOFileName resb 64 ; ISO filename canonicalization buffer |
116 | ISOFileNameEnd equ $ |
117 | CurDir resb dir_t_size ; Current directory |
118 | RootDir resb dir_t_size ; Root directory |
119 | FirstSecSum resd 1 ; Checksum of bytes 64-2048 |
120 | ImageDwords resd 1 ; isolinux.bin size, dwords |
121 | InitStack resd 1 ; Initial stack pointer (SS:SP) |
122 | DiskSys resw 1 ; Last INT 13h call |
123 | ImageSectors resw 1 ; isolinux.bin size, sectors |
124 | DiskError resb 1 ; Error code for disk I/O |
125 | DriveNo resb 1 ; CD-ROM BIOS drive number |
126 | ISOFlags resb 1 ; Flags for ISO directory search |
127 | RetryCount resb 1 ; Used for disk access retries |
128 | |
129 | _spec_start equ $ |
130 | |
131 | ; |
132 | ; El Torito spec packet |
133 | ; |
134 | |
135 | alignb 8 |
136 | spec_packet: resb 1 ; Size of packet |
137 | sp_media: resb 1 ; Media type |
138 | sp_drive: resb 1 ; Drive number |
139 | sp_controller: resb 1 ; Controller index |
140 | sp_lba: resd 1 ; LBA for emulated disk image |
141 | sp_devspec: resw 1 ; IDE/SCSI information |
142 | sp_buffer: resw 1 ; User-provided buffer |
143 | sp_loadseg: resw 1 ; Load segment |
144 | sp_sectors: resw 1 ; Sector count |
145 | sp_chs: resb 3 ; Simulated CHS geometry |
146 | sp_dummy: resb 1 ; Scratch, safe to overwrite |
147 | |
148 | ; |
149 | ; EBIOS drive parameter packet |
150 | ; |
151 | alignb 8 |
152 | drive_params: resw 1 ; Buffer size |
153 | dp_flags: resw 1 ; Information flags |
154 | dp_cyl: resd 1 ; Physical cylinders |
155 | dp_head: resd 1 ; Physical heads |
156 | dp_sec: resd 1 ; Physical sectors/track |
157 | dp_totalsec: resd 2 ; Total sectors |
158 | dp_secsize: resw 1 ; Bytes per sector |
159 | dp_dpte: resd 1 ; Device Parameter Table |
160 | dp_dpi_key: resw 1 ; 0BEDDh if rest valid |
161 | dp_dpi_len: resb 1 ; DPI len |
162 | resb 1 |
163 | resw 1 |
164 | dp_bus: resb 4 ; Host bus type |
165 | dp_interface: resb 8 ; Interface type |
166 | db_i_path: resd 2 ; Interface path |
167 | db_d_path: resd 2 ; Device path |
168 | resb 1 |
169 | db_dpi_csum: resb 1 ; Checksum for DPI info |
170 | |
171 | ; |
172 | ; EBIOS disk address packet |
173 | ; |
174 | alignb 8 |
175 | dapa: resw 1 ; Packet size |
176 | .count: resw 1 ; Block count |
177 | .off: resw 1 ; Offset of buffer |
178 | .seg: resw 1 ; Segment of buffer |
179 | .lba: resd 2 ; LBA (LSW, MSW) |
180 | |
181 | ; |
182 | ; Spec packet for disk image emulation |
183 | ; |
184 | alignb 8 |
185 | dspec_packet: resb 1 ; Size of packet |
186 | dsp_media: resb 1 ; Media type |
187 | dsp_drive: resb 1 ; Drive number |
188 | dsp_controller: resb 1 ; Controller index |
189 | dsp_lba: resd 1 ; LBA for emulated disk image |
190 | dsp_devspec: resw 1 ; IDE/SCSI information |
191 | dsp_buffer: resw 1 ; User-provided buffer |
192 | dsp_loadseg: resw 1 ; Load segment |
193 | dsp_sectors: resw 1 ; Sector count |
194 | dsp_chs: resb 3 ; Simulated CHS geometry |
195 | dsp_dummy: resb 1 ; Scratch, safe to overwrite |
196 | |
197 | alignb 4 |
198 | _spec_end equ $ |
199 | _spec_len equ _spec_end - _spec_start |
200 | |
201 | alignb open_file_t_size |
202 | Files resb MAX_OPEN*open_file_t_size |
203 | |
204 | ; |
205 | ; Constants for the xfer_buf_seg |
206 | ; |
207 | ; The xfer_buf_seg is also used to store message file buffers. We |
208 | ; need two trackbuffers (text and graphics), plus a work buffer |
209 | ; for the graphics decompressor. |
210 | ; |
211 | xbs_textbuf equ 0 ; Also hard-coded, do not change |
212 | xbs_vgabuf equ trackbufsize |
213 | xbs_vgatmpbuf equ 2*trackbufsize |
214 | |
215 | section .text |
216 | ;; |
217 | ;; Primary entry point. Because BIOSes are buggy, we only load the first |
218 | ;; CD-ROM sector (2K) of the file, so the number one priority is actually |
219 | ;; loading the rest. |
220 | ;; |
221 | StackBuf equ $ |
222 | |
223 | bootsec equ $ |
224 | |
225 | _start: ; Far jump makes sure we canonicalize the address |
226 | cli |
227 | jmp 0:_start1 |
228 | times 8-($-$$) nop ; Pad to file offset 8 |
229 | |
230 | ; This table hopefully gets filled in by mkisofs using the |
231 | ; -boot-info-table option. If not, the values in this |
232 | ; table are default values that we can use to get us what |
233 | ; we need, at least under a certain set of assumptions. |
234 | bi_pvd: dd 16 ; LBA of primary volume descriptor |
235 | bi_file: dd 0 ; LBA of boot file |
236 | bi_length: dd 0xdeadbeef ; Length of boot file |
237 | bi_csum: dd 0xdeadbeef ; Checksum of boot file |
238 | bi_reserved: times 10 dd 0xdeadbeef ; Reserved |
239 | |
240 | _start1: mov [cs:InitStack],sp ; Save initial stack pointer |
241 | mov [cs:InitStack+2],ss |
242 | xor ax,ax |
243 | mov ss,ax |
244 | mov sp,StackBuf ; Set up stack |
245 | mov ds,ax |
246 | mov es,ax |
247 | mov fs,ax |
248 | mov gs,ax |
249 | sti |
250 | |
251 | cld |
252 | ; Show signs of life |
253 | mov si,syslinux_banner |
254 | call writestr |
255 | %ifdef DEBUG_MESSAGES |
256 | mov si,copyright_str |
257 | call writestr |
258 | %endif |
259 | |
260 | ; |
261 | ; Before modifying any memory, get the checksum of bytes |
262 | ; 64-2048 |
263 | ; |
264 | initial_csum: xor edi,edi |
265 | mov si,_start1 |
266 | mov cx,(SECTOR_SIZE-64) >> 2 |
267 | .loop: lodsd |
268 | add edi,eax |
269 | loop .loop |
270 | mov [FirstSecSum],edi |
271 | |
272 | mov [DriveNo],dl |
273 | %ifdef DEBUG_MESSAGES |
274 | mov si,startup_msg |
275 | call writemsg |
276 | mov al,dl |
277 | call writehex2 |
278 | call crlf |
279 | %endif |
280 | ; |
281 | ; Initialize spec packet buffers |
282 | ; |
283 | mov di,_spec_start |
284 | mov cx,_spec_len >> 2 |
285 | xor eax,eax |
286 | rep stosd |
287 | |
288 | ; Initialize length field of the various packets |
289 | mov byte [spec_packet],13h |
290 | mov byte [drive_params],30 |
291 | mov byte [dapa],16 |
292 | mov byte [dspec_packet],13h |
293 | |
294 | ; Other nonzero fields |
295 | inc word [dsp_sectors] |
296 | |
297 | ; Now figure out what we're actually doing |
298 | ; Note: use passed-in DL value rather than 7Fh because |
299 | ; at least some BIOSes will get the wrong value otherwise |
300 | mov ax,4B01h ; Get disk emulation status |
301 | mov dl,[DriveNo] |
302 | mov si,spec_packet |
303 | int 13h |
304 | jc award_hack ; changed for BrokenAwardHack |
305 | mov dl,[DriveNo] |
306 | cmp [sp_drive],dl ; Should contain the drive number |
307 | jne spec_query_failed |
308 | |
309 | %ifdef DEBUG_MESSAGES |
310 | mov si,spec_ok_msg |
311 | call writemsg |
312 | mov al,byte [sp_drive] |
313 | call writehex2 |
314 | call crlf |
315 | %endif |
316 | |
317 | found_drive: |
318 | ; Alright, we have found the drive. Now, try to find the |
319 | ; boot file itself. If we have a boot info table, life is |
320 | ; good; if not, we have to make some assumptions, and try |
321 | ; to figure things out ourselves. In particular, the |
322 | ; assumptions we have to make are: |
323 | ; - single session only |
324 | ; - only one boot entry (no menu or other alternatives) |
325 | |
326 | cmp dword [bi_file],0 ; Address of code to load |
327 | jne found_file ; Boot info table present :) |
328 | |
329 | %ifdef DEBUG_MESSAGES |
330 | mov si,noinfotable_msg |
331 | call writemsg |
332 | %endif |
333 | |
334 | ; No such luck. See if the the spec packet contained one. |
335 | mov eax,[sp_lba] |
336 | and eax,eax |
337 | jz set_file ; Good enough |
338 | |
339 | %ifdef DEBUG_MESSAGES |
340 | mov si,noinfoinspec_msg |
341 | call writemsg |
342 | %endif |
343 | |
344 | ; No such luck. Get the Boot Record Volume, assuming single |
345 | ; session disk, and that we're the first entry in the chain |
346 | mov eax,17 ; Assumed address of BRV |
347 | mov bx,trackbuf |
348 | call getonesec |
349 | |
350 | mov eax,[trackbuf+47h] ; Get boot catalog address |
351 | mov bx,trackbuf |
352 | call getonesec ; Get boot catalog |
353 | |
354 | mov eax,[trackbuf+28h] ; First boot entry |
355 | ; And hope and pray this is us... |
356 | |
357 | ; Some BIOSes apparently have limitations on the size |
358 | ; that may be loaded (despite the El Torito spec being very |
359 | ; clear on the fact that it must all be loaded.) Therefore, |
360 | ; we load it ourselves, and *bleep* the BIOS. |
361 | |
362 | set_file: |
363 | mov [bi_file],eax |
364 | |
365 | found_file: |
366 | ; Set up boot file sizes |
367 | mov eax,[bi_length] |
368 | sub eax,SECTOR_SIZE-3 |
369 | shr eax,2 ; bytes->dwords |
370 | mov [ImageDwords],eax ; boot file dwords |
371 | add eax,(2047 >> 2) |
372 | shr eax,9 ; dwords->sectors |
373 | mov [ImageSectors],ax ; boot file sectors |
374 | |
375 | mov eax,[bi_file] ; Address of code to load |
376 | inc eax ; Don't reload bootstrap code |
377 | %ifdef DEBUG_MESSAGES |
378 | mov si,offset_msg |
379 | call writemsg |
380 | call writehex8 |
381 | call crlf |
382 | %endif |
383 | |
384 | ; Just in case some BIOSes have problems with |
385 | ; segment wraparound, use the normalized address |
386 | mov bx,((7C00h+2048) >> 4) |
387 | mov es,bx |
388 | xor bx,bx |
389 | mov bp,[ImageSectors] |
390 | %ifdef DEBUG_MESSAGES |
391 | push ax |
392 | mov si,size_msg |
393 | call writemsg |
394 | mov ax,bp |
395 | call writehex4 |
396 | call crlf |
397 | pop ax |
398 | %endif |
399 | call getlinsec |
400 | |
401 | push ds |
402 | pop es |
403 | |
404 | %ifdef DEBUG_MESSAGES |
405 | mov si,loaded_msg |
406 | call writemsg |
407 | %endif |
408 | |
409 | ; Verify the checksum on the loaded image. |
410 | verify_image: |
411 | mov si,7C00h+2048 |
412 | mov bx,es |
413 | mov ecx,[ImageDwords] |
414 | mov edi,[FirstSecSum] ; First sector checksum |
415 | .loop es lodsd |
416 | add edi,eax |
417 | dec ecx |
418 | jz .done |
419 | and si,si |
420 | jnz .loop |
421 | ; SI wrapped around, advance ES |
422 | add bx,1000h |
423 | mov es,bx |
424 | jmp short .loop |
425 | .done: mov ax,ds |
426 | mov es,ax |
427 | cmp [bi_csum],edi |
428 | je integrity_ok |
429 | |
430 | mov si,checkerr_msg |
431 | call writemsg |
432 | jmp kaboom |
433 | |
434 | integrity_ok: |
435 | %ifdef DEBUG_MESSAGES |
436 | mov si,allread_msg |
437 | call writemsg |
438 | %endif |
439 | jmp all_read ; Jump to main code |
440 | |
441 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
442 | ;; Start of BrokenAwardHack --- 10-nov-2002 Knut_Petersen@t-online.de |
443 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
444 | ;; |
445 | ;; There is a problem with certain versions of the AWARD BIOS ... |
446 | ;; the boot sector will be loaded and executed correctly, but, because the |
447 | ;; int 13 vector points to the wrong code in the BIOS, every attempt to |
448 | ;; load the spec packet will fail. We scan for the equivalent of |
449 | ;; |
450 | ;; mov ax,0201h |
451 | ;; mov bx,7c00h |
452 | ;; mov cx,0006h |
453 | ;; mov dx,0180h |
454 | ;; pushf |
455 | ;; call <direct far> |
456 | ;; |
457 | ;; and use <direct far> as the new vector for int 13. The code above is |
458 | ;; used to load the boot code into ram, and there should be no reason |
459 | ;; for anybody to change it now or in the future. There are no opcodes |
460 | ;; that use encodings relativ to IP, so scanning is easy. If we find the |
461 | ;; code above in the BIOS code we can be pretty sure to run on a machine |
462 | ;; with an broken AWARD BIOS ... |
463 | ;; |
464 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
465 | ;; |
466 | %ifdef DEBUG_MESSAGES ;; |
467 | ;; |
468 | award_notice db "Trying BrokenAwardHack first ...",CR,LF,0 ;; |
469 | award_not_orig db "BAH: Original Int 13 vector : ",0 ;; |
470 | award_not_new db "BAH: Int 13 vector changed to : ",0 ;; |
471 | award_not_succ db "BAH: SUCCESS",CR,LF,0 ;; |
472 | award_not_fail db "BAH: FAILURE" ;; |
473 | award_not_crlf db CR,LF,0 ;; |
474 | ;; |
475 | %endif ;; |
476 | ;; |
477 | award_oldint13 dd 0 ;; |
478 | award_string db 0b8h,1,2,0bbh,0,7ch,0b9h,6,0,0bah,80h,1,09ch,09ah ;; |
479 | ;; |
480 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
481 | award_hack: mov si,spec_err_msg ; Moved to this place from |
482 | call writemsg ; spec_query_faild |
483 | ; |
484 | %ifdef DEBUG_MESSAGES ; |
485 | ; |
486 | mov si,award_notice ; display our plan |
487 | call writemsg ; |
488 | mov si,award_not_orig ; display original int 13 |
489 | call writemsg ; vector |
490 | %endif ; |
491 | mov eax,[13h*4] ; |
492 | mov [award_oldint13],eax ; |
493 | ; |
494 | %ifdef DEBUG_MESSAGES ; |
495 | ; |
496 | call writehex8 ; |
497 | mov si,award_not_crlf ; |
498 | call writestr ; |
499 | %endif ; |
500 | push es ; save ES |
501 | mov ax,0f000h ; ES = BIOS Seg |
502 | mov es,ax ; |
503 | cld ; |
504 | xor di,di ; start at ES:DI = f000:0 |
505 | award_loop: push di ; save DI |
506 | mov si,award_string ; scan for award_string |
507 | mov cx,7 ; length of award_string = 7dw |
508 | repz cmpsw ; compare |
509 | pop di ; restore DI |
510 | jcxz award_found ; jmp if found |
511 | inc di ; not found, inc di |
512 | jno award_loop ; |
513 | ; |
514 | award_failed: pop es ; No, not this way :-(( |
515 | award_fail2: ; |
516 | ; |
517 | %ifdef DEBUG_MESSAGES ; |
518 | ; |
519 | mov si,award_not_fail ; display failure ... |
520 | call writemsg ; |
521 | %endif ; |
522 | mov eax,[award_oldint13] ; restore the original int |
523 | or eax,eax ; 13 vector if there is one |
524 | jz spec_query_failed ; and try other workarounds |
525 | mov [13h*4],eax ; |
526 | jmp spec_query_failed ; |
527 | ; |
528 | award_found: mov eax,[es:di+0eh] ; load possible int 13 addr |
529 | pop es ; restore ES |
530 | ; |
531 | cmp eax,[award_oldint13] ; give up if this is the |
532 | jz award_failed ; active int 13 vector, |
533 | mov [13h*4],eax ; otherwise change 0:13h*4 |
534 | ; |
535 | ; |
536 | %ifdef DEBUG_MESSAGES ; |
537 | ; |
538 | push eax ; display message and |
539 | mov si,award_not_new ; new vector address |
540 | call writemsg ; |
541 | pop eax ; |
542 | call writehex8 ; |
543 | mov si,award_not_crlf ; |
544 | call writestr ; |
545 | %endif ; |
546 | mov ax,4B01h ; try to read the spec packet |
547 | mov dl,[DriveNo] ; now ... it should not fail |
548 | mov si,spec_packet ; any longer |
549 | int 13h ; |
550 | jc award_fail2 ; |
551 | ; |
552 | %ifdef DEBUG_MESSAGES ; |
553 | ; |
554 | mov si,award_not_succ ; display our SUCCESS |
555 | call writemsg ; |
556 | %endif ; |
557 | jmp found_drive ; and leave error recovery code |
558 | ; |
559 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
560 | ;; End of BrokenAwardHack ---- 10-nov-2002 Knut_Petersen@t-online.de |
561 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
562 | |
563 | |
564 | ; INT 13h, AX=4B01h, DL=<passed in value> failed. |
565 | ; Try to scan the entire 80h-FFh from the end. |
566 | |
567 | spec_query_failed: |
568 | |
569 | ; some code moved to BrokenAwardHack |
570 | |
571 | mov dl,0FFh |
572 | .test_loop: pusha |
573 | mov ax,4B01h |
574 | mov si,spec_packet |
575 | mov byte [si],13 ; Size of buffer |
576 | int 13h |
577 | popa |
578 | jc .still_broken |
579 | |
580 | mov si,maybe_msg |
581 | call writemsg |
582 | mov al,dl |
583 | call writehex2 |
584 | call crlf |
585 | |
586 | cmp byte [sp_drive],dl |
587 | jne .maybe_broken |
588 | |
589 | ; Okay, good enough... |
590 | mov si,alright_msg |
591 | call writemsg |
592 | mov [DriveNo],dl |
593 | .found_drive: jmp found_drive |
594 | |
595 | ; Award BIOS 4.51 apparently passes garbage in sp_drive, |
596 | ; but if this was the drive number originally passed in |
597 | ; DL then consider it "good enough" |
598 | .maybe_broken: |
599 | cmp byte [DriveNo],dl |
600 | je .found_drive |
601 | |
602 | .still_broken: dec dx |
603 | cmp dl, 80h |
604 | jnb .test_loop |
605 | |
606 | ; No spec packet anywhere. Some particularly pathetic |
607 | ; BIOSes apparently don't even implement function |
608 | ; 4B01h, so we can't query a spec packet no matter |
609 | ; what. If we got a drive number in DL, then try to |
610 | ; use it, and if it works, then well... |
611 | mov dl,[DriveNo] |
612 | cmp dl,81h ; Should be 81-FF at least |
613 | jb fatal_error ; If not, it's hopeless |
614 | |
615 | ; Write a warning to indicate we're on *very* thin ice now |
616 | mov si,nospec_msg |
617 | call writemsg |
618 | mov al,dl |
619 | call writehex2 |
620 | call crlf |
621 | mov si,trysbm_msg |
622 | call writemsg |
623 | jmp .found_drive ; Pray that this works... |
624 | |
625 | fatal_error: |
626 | mov si,nothing_msg |
627 | call writemsg |
628 | |
629 | .norge: jmp short .norge |
630 | |
631 | ; Information message (DS:SI) output |
632 | ; Prefix with "isolinux: " |
633 | ; |
634 | writemsg: push ax |
635 | push si |
636 | mov si,isolinux_str |
637 | call writestr |
638 | pop si |
639 | call writestr |
640 | pop ax |
641 | ret |
642 | |
643 | ; |
644 | ; Write a character to the screen. There is a more "sophisticated" |
645 | ; version of this in the subsequent code, so we patch the pointer |
646 | ; when appropriate. |
647 | ; |
648 | |
649 | writechr: |
650 | jmp near writechr_simple ; 3-byte jump |
651 | |
652 | writechr_simple: |
653 | pushfd |
654 | pushad |
655 | mov ah,0Eh |
656 | xor bx,bx |
657 | int 10h |
658 | popad |
659 | popfd |
660 | ret |
661 | |
662 | ; |
663 | ; Get one sector. Convenience entry point. |
664 | ; |
665 | getonesec: |
666 | mov bp,1 |
667 | ; Fall through to getlinsec |
668 | |
669 | ; |
670 | ; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors. |
671 | ; |
672 | ; Note that we can't always do this as a single request, because at least |
673 | ; Phoenix BIOSes has a 127-sector limit. To be on the safe side, stick |
674 | ; to 32 sectors (64K) per request. |
675 | ; |
676 | ; Input: |
677 | ; EAX - Linear sector number |
678 | ; ES:BX - Target buffer |
679 | ; BP - Sector count |
680 | ; |
681 | getlinsec: |
682 | mov si,dapa ; Load up the DAPA |
683 | mov [si+4],bx |
684 | mov bx,es |
685 | mov [si+6],bx |
686 | mov [si+8],eax |
687 | .loop: |
688 | push bp ; Sectors left |
689 | cmp bp,[MaxTransfer] |
690 | jbe .bp_ok |
691 | mov bp,[MaxTransfer] |
692 | .bp_ok: |
693 | mov [si+2],bp |
694 | push si |
695 | mov dl,[DriveNo] |
696 | mov ah,42h ; Extended Read |
697 | call xint13 |
698 | pop si |
699 | pop bp |
700 | movzx eax,word [si+2] ; Sectors we read |
701 | add [si+8],eax ; Advance sector pointer |
702 | sub bp,ax ; Sectors left |
703 | shl ax,SECTOR_SHIFT-4 ; 2048-byte sectors -> segment |
704 | add [si+6],ax ; Advance buffer pointer |
705 | and bp,bp |
706 | jnz .loop |
707 | mov eax,[si+8] ; Next sector |
708 | ret |
709 | |
710 | ; INT 13h with retry |
711 | xint13: mov byte [RetryCount],retry_count |
712 | .try: pushad |
713 | int 13h |
714 | jc .error |
715 | add sp,byte 8*4 ; Clean up stack |
716 | ret |
717 | .error: |
718 | mov [DiskError],ah ; Save error code |
719 | popad |
720 | mov [DiskSys],ax ; Save system call number |
721 | dec byte [RetryCount] |
722 | jz .real_error |
723 | push ax |
724 | mov al,[RetryCount] |
725 | mov ah,[dapa+2] ; Sector transfer count |
726 | cmp al,2 ; Only 2 attempts left |
727 | ja .nodanger |
728 | mov ah,1 ; Drop transfer size to 1 |
729 | jmp short .setsize |
730 | .nodanger: |
731 | cmp al,retry_count-2 |
732 | ja .again ; First time, just try again |
733 | shr ah,1 ; Otherwise, try to reduce |
734 | adc ah,0 ; the max transfer size, but not to 0 |
735 | .setsize: |
736 | mov [MaxTransfer],ah |
737 | mov [dapa+2],ah |
738 | .again: |
739 | pop ax |
740 | jmp .try |
741 | |
742 | .real_error: mov si,diskerr_msg |
743 | call writemsg |
744 | mov al,[DiskError] |
745 | call writehex2 |
746 | mov si,oncall_str |
747 | call writestr |
748 | mov ax,[DiskSys] |
749 | call writehex4 |
750 | mov si,ondrive_str |
751 | call writestr |
752 | mov al,dl |
753 | call writehex2 |
754 | call crlf |
755 | ; Fall through to kaboom |
756 | |
757 | ; |
758 | ; kaboom: write a message and bail out. Wait for a user keypress, |
759 | ; then do a hard reboot. |
760 | ; |
761 | kaboom: |
762 | lss sp,[cs:StackPtr] |
763 | mov ax,cs |
764 | mov ds,ax |
765 | mov es,ax |
766 | mov fs,ax |
767 | mov gs,ax |
768 | sti |
769 | mov si,err_bootfailed |
770 | call cwritestr |
771 | call getchar |
772 | cli |
773 | mov word [BIOS_magic],0 ; Cold reboot |
774 | jmp 0F000h:0FFF0h ; Reset vector address |
775 | |
776 | ; ----------------------------------------------------------------------------- |
777 | ; Common modules needed in the first sector |
778 | ; ----------------------------------------------------------------------------- |
779 | |
780 | %include "writestr.inc" ; String output |
781 | writestr equ cwritestr |
782 | %include "writehex.inc" ; Hexadecimal output |
783 | |
784 | ; ----------------------------------------------------------------------------- |
785 | ; Data that needs to be in the first sector |
786 | ; ----------------------------------------------------------------------------- |
787 | |
788 | syslinux_banner db CR, LF, 'ISOLINUX ', version_str, ' ', date, ' ', 0 |
789 | copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin' |
790 | db CR, LF, 0 |
791 | isolinux_str db 'isolinux: ', 0 |
792 | %ifdef DEBUG_MESSAGES |
793 | startup_msg: db 'Starting up, DL = ', 0 |
794 | spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0 |
795 | secsize_msg: db 'Sector size appears to be ', 0 |
796 | offset_msg: db 'Loading main image from LBA = ', 0 |
797 | size_msg: db 'Sectors to load = ', 0 |
798 | loaded_msg: db 'Loaded boot image, verifying...', CR, LF, 0 |
799 | verify_msg: db 'Image checksum verified.', CR, LF, 0 |
800 | allread_msg db 'Main image read, jumping to main code...', CR, LF, 0 |
801 | %endif |
802 | noinfotable_msg db 'No boot info table, assuming single session disk...', CR, LF, 0 |
803 | noinfoinspec_msg db 'Spec packet missing LBA information, trying to wing it...', CR, LF, 0 |
804 | spec_err_msg: db 'Loading spec packet failed, trying to wing it...', CR, LF, 0 |
805 | maybe_msg: db 'Found something at drive = ', 0 |
806 | alright_msg: db 'Looks like it might be right, continuing...', CR, LF, 0 |
807 | nospec_msg db 'Extremely broken BIOS detected, last ditch attempt with drive = ', 0 |
808 | nothing_msg: db 'Failed to locate CD-ROM device; boot failed.', CR, LF |
809 | trysbm_msg db 'See http://syslinux.zytor.com/sbm for more information.', CR, LF, 0 |
810 | diskerr_msg: db 'Disk error ', 0 |
811 | oncall_str: db ', AX = ',0 |
812 | ondrive_str: db ', drive ', 0 |
813 | checkerr_msg: db 'Image checksum error, sorry...', CR, LF, 0 |
814 | |
815 | err_bootfailed db CR, LF, 'Boot failed: press a key to retry...' |
816 | bailmsg equ err_bootfailed |
817 | crlf_msg db CR, LF |
818 | null_msg db 0 |
819 | |
820 | alignb 4, db 0 |
821 | StackPtr dw StackBuf, 0 ; SS:SP for stack reset |
822 | MaxTransfer dw 32 ; Max sectors per transfer |
823 | |
824 | rl_checkpt equ $ ; Must be <= 800h |
825 | |
826 | rl_checkpt_off equ ($-$$) |
827 | ;%ifndef DEPEND |
828 | ;%if rl_checkpt_off > 0x800 |
829 | ;%error "Sector 0 overflow" |
830 | ;%endif |
831 | ;%endif |
832 | |
833 | ; ---------------------------------------------------------------------------- |
834 | ; End of code and data that have to be in the first sector |
835 | ; ---------------------------------------------------------------------------- |
836 | |
837 | all_read: |
838 | ; |
839 | ; Initialize screen (if we're using one) |
840 | ; |
841 | ; Now set up screen parameters |
842 | call adjust_screen |
843 | |
844 | ; Wipe the F-key area |
845 | mov al,NULLFILE |
846 | mov di,FKeyName |
847 | mov cx,10*(1 << FILENAME_MAX_LG2) |
848 | rep stosb |
849 | |
850 | ; Patch the writechr routine to point to the full code |
851 | mov word [writechr+1], writechr_full-(writechr+3) |
852 | |
853 | ; Tell the user we got this far... |
854 | %ifndef DEBUG_MESSAGES ; Gets messy with debugging on |
855 | mov si,copyright_str |
856 | call writestr |
857 | %endif |
858 | |
859 | ; Test tracers |
860 | TRACER 'T' |
861 | TRACER '>' |
862 | |
863 | ; |
864 | ; Common initialization code |
865 | ; |
866 | %include "init.inc" |
867 | %include "cpuinit.inc" |
868 | |
869 | ; |
870 | ; Now we're all set to start with our *real* business. First load the |
871 | ; configuration file (if any) and parse it. |
872 | ; |
873 | ; In previous versions I avoided using 32-bit registers because of a |
874 | ; rumour some BIOSes clobbered the upper half of 32-bit registers at |
875 | ; random. I figure, though, that if there are any of those still left |
876 | ; they probably won't be trying to install Linux on them... |
877 | ; |
878 | ; The code is still ripe with 16-bitisms, though. Not worth the hassle |
879 | ; to take'm out. In fact, we may want to put them back if we're going |
880 | ; to boot ELKS at some point. |
881 | ; |
882 | |
883 | ; |
884 | ; Now, we need to sniff out the actual filesystem data structures. |
885 | ; mkisofs gave us a pointer to the primary volume descriptor |
886 | ; (which will be at 16 only for a single-session disk!); from the PVD |
887 | ; we should be able to find the rest of what we need to know. |
888 | ; |
889 | get_fs_structures: |
890 | mov eax,[bi_pvd] |
891 | mov bx,trackbuf |
892 | call getonesec |
893 | |
894 | mov eax,[trackbuf+156+2] |
895 | mov [RootDir+dir_lba],eax |
896 | mov [CurDir+dir_lba],eax |
897 | %ifdef DEBUG_MESSAGES |
898 | mov si,dbg_rootdir_msg |
899 | call writemsg |
900 | call writehex8 |
901 | call crlf |
902 | %endif |
903 | mov eax,[trackbuf+156+10] |
904 | mov [RootDir+dir_len],eax |
905 | mov [CurDir+dir_len],eax |
906 | add eax,SECTOR_SIZE-1 |
907 | shr eax,SECTOR_SHIFT |
908 | mov [RootDir+dir_clust],eax |
909 | mov [CurDir+dir_clust],eax |
910 | |
911 | ; Look for an isolinux directory, and if found, |
912 | ; make it the current directory instead of the root |
913 | ; directory. |
914 | mov di,boot_dir ; Search for /boot/isolinux |
915 | mov al,02h |
916 | call searchdir_iso |
917 | jnz .found_dir |
918 | mov di,isolinux_dir |
919 | mov al,02h ; Search for /isolinux |
920 | call searchdir_iso |
921 | jz .no_isolinux_dir |
922 | .found_dir: |
923 | mov [CurDir+dir_len],eax |
924 | mov eax,[si+file_left] |
925 | mov [CurDir+dir_clust],eax |
926 | xor eax,eax ; Free this file pointer entry |
927 | xchg eax,[si+file_sector] |
928 | mov [CurDir+dir_lba],eax |
929 | %ifdef DEBUG_MESSAGES |
930 | push si |
931 | mov si,dbg_isodir_msg |
932 | call writemsg |
933 | pop si |
934 | call writehex8 |
935 | call crlf |
936 | %endif |
937 | .no_isolinux_dir: |
938 | |
939 | ; |
940 | ; Locate the configuration file |
941 | ; |
942 | load_config: |
943 | %ifdef DEBUG_MESSAGES |
944 | mov si,dbg_config_msg |
945 | call writemsg |
946 | %endif |
947 | |
948 | mov di,isolinux_cfg |
949 | call open |
950 | jz no_config_file ; Not found or empty |
951 | |
952 | %ifdef DEBUG_MESSAGES |
953 | mov si,dbg_configok_msg |
954 | call writemsg |
955 | %endif |
956 | |
957 | ; |
958 | ; Now we have the config file open. Parse the config file and |
959 | ; run the user interface. |
960 | ; |
961 | %include "ui.inc" |
962 | |
963 | ; |
964 | ; Linux kernel loading code is common. |
965 | ; |
966 | %include "runkernel.inc" |
967 | |
968 | ; |
969 | ; COMBOOT-loading code |
970 | ; |
971 | %include "comboot.inc" |
972 | %include "com32.inc" |
973 | %include "cmdline.inc" |
974 | |
975 | ; |
976 | ; Boot sector loading code |
977 | ; |
978 | %include "bootsect.inc" |
979 | |
980 | ; |
981 | ; Enable disk emulation. The kind of disk we emulate is dependent on the size of |
982 | ; the file: 1200K, 1440K or 2880K floppy, otherwise harddisk. |
983 | ; |
984 | is_disk_image: |
985 | TRACER CR |
986 | TRACER LF |
987 | TRACER 'D' |
988 | TRACER ':' |
989 | |
990 | shl edx,16 |
991 | mov dx,ax ; Set EDX <- file size |
992 | mov di,img_table |
993 | mov cx,img_table_count |
994 | mov eax,[si+file_sector] ; Starting LBA of file |
995 | mov [dsp_lba],eax ; Location of file |
996 | mov byte [dsp_drive], 0 ; 00h floppy, 80h hard disk |
997 | .search_table: |
998 | TRACER 't' |
999 | mov eax,[di+4] |
1000 | cmp edx,[di] |
1001 | je .type_found |
1002 | add di,8 |
1003 | loop .search_table |
1004 | |
1005 | ; Hard disk image. Need to examine the partition table |
1006 | ; in order to deduce the C/H/S geometry. Sigh. |
1007 | .hard_disk_image: |
1008 | TRACER 'h' |
1009 | cmp edx,512 |
1010 | jb .bad_image |
1011 | |
1012 | mov bx,trackbuf |
1013 | mov cx,1 ; Load 1 sector |
1014 | call getfssec |
1015 | |
1016 | cmp word [trackbuf+510],0aa55h ; Boot signature |
1017 | jne .bad_image ; Image not bootable |
1018 | |
1019 | mov cx,4 ; 4 partition entries |
1020 | mov di,trackbuf+446 ; Start of partition table |
1021 | |
1022 | xor ax,ax ; Highest sector(al) head(ah) |
1023 | |
1024 | .part_scan: |
1025 | cmp byte [di+4], 0 |
1026 | jz .part_loop |
1027 | lea si,[di+1] |
1028 | call .hs_check |
1029 | add si,byte 4 |
1030 | call .hs_check |
1031 | .part_loop: |
1032 | add di,byte 16 |
1033 | loop .part_scan |
1034 | |
1035 | push eax ; H/S |
1036 | push edx ; File size |
1037 | mov bl,ah |
1038 | xor bh,bh |
1039 | inc bx ; # of heads in BX |
1040 | xor ah,ah ; # of sectors in AX |
1041 | cwde ; EAX[31:16] <- 0 |
1042 | mul bx |
1043 | shl eax,9 ; Convert to bytes |
1044 | ; Now eax contains the number of bytes per cylinder |
1045 | pop ebx ; File size |
1046 | xor edx,edx |
1047 | div ebx |
1048 | and edx,edx |
1049 | jz .no_remainder |
1050 | inc eax ; Fractional cylinder... |
1051 | ; Now (e)ax contains the number of cylinders |
1052 | .no_remainder: cmp eax,1024 |
1053 | jna .ok_cyl |
1054 | mov ax,1024 ; Max possible # |
1055 | .ok_cyl: dec ax ; Convert to max cylinder no |
1056 | pop ebx ; S(bl) H(bh) |
1057 | shl ah,6 |
1058 | or bl,ah |
1059 | xchg ax,bx |
1060 | shl eax,16 |
1061 | mov ah,bl |
1062 | mov al,4 ; Hard disk boot |
1063 | mov byte [dsp_drive], 80h ; Drive 80h = hard disk |
1064 | |
1065 | .type_found: |
1066 | TRACER 'T' |
1067 | mov bl,[sp_media] |
1068 | and bl,0F0h ; Copy controller info bits |
1069 | or al,bl |
1070 | mov [dsp_media],al ; Emulation type |
1071 | shr eax,8 |
1072 | mov [dsp_chs],eax ; C/H/S geometry |
1073 | mov ax,[sp_devspec] ; Copy device spec |
1074 | mov [dsp_devspec],ax |
1075 | mov al,[sp_controller] ; Copy controller index |
1076 | mov [dsp_controller],al |
1077 | |
1078 | TRACER 'V' |
1079 | call vgaclearmode ; Reset video |
1080 | |
1081 | mov ax,4C00h ; Enable emulation and boot |
1082 | mov si,dspec_packet |
1083 | mov dl,[DriveNo] |
1084 | lss sp,[InitStack] |
1085 | TRACER 'X' |
1086 | |
1087 | int 13h |
1088 | |
1089 | ; If this returns, we have problems |
1090 | .bad_image: |
1091 | mov si,err_disk_image |
1092 | call cwritestr |
1093 | jmp enter_command |
1094 | |
1095 | ; |
1096 | ; Look for the highest seen H/S geometry |
1097 | ; We compute cylinders separately |
1098 | ; |
1099 | .hs_check: |
1100 | mov bl,[si] ; Head # |
1101 | cmp bl,ah |
1102 | jna .done_track |
1103 | mov ah,bl ; New highest head # |
1104 | .done_track: mov bl,[si+1] |
1105 | and bl,3Fh ; Sector # |
1106 | cmp bl,al |
1107 | jna .done_sector |
1108 | mov al,bl |
1109 | .done_sector: ret |
1110 | |
1111 | ; |
1112 | ; Boot a specified local disk. AX specifies the BIOS disk number; or |
1113 | ; 0xFFFF in case we should execute INT 18h ("next device.") |
1114 | ; |
1115 | local_boot: |
1116 | call vgaclearmode |
1117 | lss sp,[cs:Stack] ; Restore stack pointer |
1118 | xor dx,dx |
1119 | mov ds,dx |
1120 | mov es,dx |
1121 | mov fs,dx |
1122 | mov gs,dx |
1123 | mov si,localboot_msg |
1124 | call writestr |
1125 | cmp ax,-1 |
1126 | je .int18 |
1127 | |
1128 | ; Load boot sector from the specified BIOS device and jump to it. |
1129 | mov dl,al |
1130 | xor dh,dh |
1131 | push dx |
1132 | xor ax,ax ; Reset drive |
1133 | call xint13 |
1134 | mov ax,0201h ; Read one sector |
1135 | mov cx,0001h ; C/H/S = 0/0/1 (first sector) |
1136 | mov bx,trackbuf |
1137 | call xint13 |
1138 | pop dx |
1139 | cli ; Abandon hope, ye who enter here |
1140 | mov si,trackbuf |
1141 | mov di,07C00h |
1142 | mov cx,512 ; Probably overkill, but should be safe |
1143 | rep movsd |
1144 | lss sp,[cs:InitStack] |
1145 | jmp 0:07C00h ; Jump to new boot sector |
1146 | |
1147 | .int18: |
1148 | int 18h ; Hope this does the right thing... |
1149 | jmp kaboom ; If we returned, oh boy... |
1150 | |
1151 | ; |
1152 | ; Abort loading code |
1153 | ; |
1154 | %include "abort.inc" |
1155 | |
1156 | ; |
1157 | ; searchdir: |
1158 | ; |
1159 | ; Open a file |
1160 | ; |
1161 | ; On entry: |
1162 | ; DS:DI = filename |
1163 | ; If successful: |
1164 | ; ZF clear |
1165 | ; SI = file pointer |
1166 | ; DX:AX or EAX = file length in bytes |
1167 | ; If unsuccessful |
1168 | ; ZF set |
1169 | ; |
1170 | ; Assumes CS == DS == ES, and trashes BX and CX. |
1171 | ; |
1172 | ; searchdir_iso is a special entry point for ISOLINUX only. In addition |
1173 | ; to the above, searchdir_iso passes a file flag mask in AL. This is useful |
1174 | ; for searching for directories. |
1175 | ; |
1176 | alloc_failure: |
1177 | xor ax,ax ; ZF <- 1 |
1178 | ret |
1179 | |
1180 | searchdir: |
1181 | xor al,al |
1182 | searchdir_iso: |
1183 | mov [ISOFlags],al |
1184 | TRACER 'S' |
1185 | call allocate_file ; Temporary file structure for directory |
1186 | jnz alloc_failure |
1187 | push es |
1188 | push ds |
1189 | pop es ; ES = DS |
1190 | mov si,CurDir |
1191 | cmp byte [di],'/' ; If filename begins with slash |
1192 | jne .not_rooted |
1193 | inc di ; Skip leading slash |
1194 | mov si,RootDir ; Reference root directory instead |
1195 | .not_rooted: |
1196 | mov eax,[si+dir_clust] |
1197 | mov [bx+file_left],eax |
1198 | mov eax,[si+dir_lba] |
1199 | mov [bx+file_sector],eax |
1200 | mov edx,[si+dir_len] |
1201 | |
1202 | .look_for_slash: |
1203 | mov ax,di |
1204 | .scan: |
1205 | mov cl,[di] |
1206 | inc di |
1207 | and cl,cl |
1208 | jz .isfile |
1209 | cmp cl,'/' |
1210 | jne .scan |
1211 | mov [di-1],byte 0 ; Terminate at directory name |
1212 | mov cl,02h ; Search for directory |
1213 | xchg cl,[ISOFlags] |
1214 | |
1215 | push di ; Save these... |
1216 | push cx |
1217 | |
1218 | ; Create recursion stack frame... |
1219 | push word .resume ; Where to "return" to |
1220 | push es |
1221 | .isfile: xchg ax,di |
1222 | |
1223 | .getsome: |
1224 | ; Get a chunk of the directory |
1225 | ; This relies on the fact that ISOLINUX doesn't change SI |
1226 | mov si,trackbuf |
1227 | TRACER 'g' |
1228 | pushad |
1229 | xchg bx,si |
1230 | mov cx,[BufSafe] |
1231 | call getfssec |
1232 | popad |
1233 | |
1234 | .compare: |
1235 | movzx eax,byte [si] ; Length of directory entry |
1236 | cmp al,33 |
1237 | jb .next_sector |
1238 | TRACER 'c' |
1239 | mov cl,[si+25] |
1240 | xor cl,[ISOFlags] |
1241 | test cl, byte 8Eh ; Unwanted file attributes! |
1242 | jnz .not_file |
1243 | pusha |
1244 | movzx cx,byte [si+32] ; File identifier length |
1245 | add si,byte 33 ; File identifier offset |
1246 | TRACER 'i' |
1247 | call iso_compare_names |
1248 | popa |
1249 | je .success |
1250 | .not_file: |
1251 | sub edx,eax ; Decrease bytes left |
1252 | jbe .failure |
1253 | add si,ax ; Advance pointer |
1254 | |
1255 | .check_overrun: |
1256 | ; Did we finish the buffer? |
1257 | cmp si,trackbuf+trackbufsize |
1258 | jb .compare ; No, keep going |
1259 | |
1260 | jmp short .getsome ; Get some more directory |
1261 | |
1262 | .next_sector: |
1263 | ; Advance to the beginning of next sector |
1264 | lea ax,[si+SECTOR_SIZE-1] |
1265 | and ax,~(SECTOR_SIZE-1) |
1266 | sub ax,si |
1267 | jmp short .not_file ; We still need to do length checks |
1268 | |
1269 | .failure: xor eax,eax ; ZF = 1 |
1270 | mov [bx+file_sector],eax |
1271 | pop es |
1272 | ret |
1273 | |
1274 | .success: |
1275 | mov eax,[si+2] ; Location of extent |
1276 | mov [bx+file_sector],eax |
1277 | mov eax,[si+10] ; Data length |
1278 | push eax |
1279 | add eax,SECTOR_SIZE-1 |
1280 | shr eax,SECTOR_SHIFT |
1281 | mov [bx+file_left],eax |
1282 | pop eax |
1283 | mov edx,eax |
1284 | shr edx,16 |
1285 | and bx,bx ; ZF = 0 |
1286 | mov si,bx |
1287 | pop es |
1288 | ret |
1289 | |
1290 | .resume: ; We get here if we were only doing part of a lookup |
1291 | ; This relies on the fact that .success returns bx == si |
1292 | xchg edx,eax ; Directory length in edx |
1293 | pop cx ; Old ISOFlags |
1294 | pop di ; Next filename pointer |
1295 | mov byte [di-1], '/' ; Restore slash |
1296 | mov [ISOFlags],cl ; Restore the flags |
1297 | jz .failure ; Did we fail? If so fail for real! |
1298 | jmp .look_for_slash ; Otherwise, next level |
1299 | |
1300 | ; |
1301 | ; allocate_file: Allocate a file structure |
1302 | ; |
1303 | ; If successful: |
1304 | ; ZF set |
1305 | ; BX = file pointer |
1306 | ; In unsuccessful: |
1307 | ; ZF clear |
1308 | ; |
1309 | allocate_file: |
1310 | TRACER 'a' |
1311 | push cx |
1312 | mov bx,Files |
1313 | mov cx,MAX_OPEN |
1314 | .check: cmp dword [bx], byte 0 |
1315 | je .found |
1316 | add bx,open_file_t_size ; ZF = 0 |
1317 | loop .check |
1318 | ; ZF = 0 if we fell out of the loop |
1319 | .found: pop cx |
1320 | ret |
1321 | |
1322 | ; |
1323 | ; iso_compare_names: |
1324 | ; Compare the names DS:SI and DS:DI and report if they are |
1325 | ; equal from an ISO 9660 perspective. SI is the name from |
1326 | ; the filesystem; CX indicates its length, and ';' terminates. |
1327 | ; DI is expected to end with a null. |
1328 | ; |
1329 | ; Note: clobbers AX, CX, SI, DI; assumes DS == ES == base segment |
1330 | ; |
1331 | |
1332 | iso_compare_names: |
1333 | ; First, terminate and canonicalize input filename |
1334 | push di |
1335 | mov di,ISOFileName |
1336 | .canon_loop: jcxz .canon_end |
1337 | lodsb |
1338 | dec cx |
1339 | cmp al,';' |
1340 | je .canon_end |
1341 | and al,al |
1342 | je .canon_end |
1343 | stosb |
1344 | cmp di,ISOFileNameEnd-1 ; Guard against buffer overrun |
1345 | jb .canon_loop |
1346 | .canon_end: |
1347 | cmp di,ISOFileName |
1348 | jbe .canon_done |
1349 | cmp byte [di-1],'.' ; Remove terminal dots |
1350 | jne .canon_done |
1351 | dec di |
1352 | jmp short .canon_end |
1353 | .canon_done: |
1354 | mov [di],byte 0 ; Null-terminate string |
1355 | pop di |
1356 | mov si,ISOFileName |
1357 | .compare: |
1358 | lodsb |
1359 | mov ah,[di] |
1360 | inc di |
1361 | and ax,ax |
1362 | jz .success ; End of string for both |
1363 | and al,al ; Is either one end of string? |
1364 | jz .failure ; If so, failure |
1365 | and ah,ah |
1366 | jz .failure |
1367 | or ax,2020h ; Convert to lower case |
1368 | cmp al,ah |
1369 | je .compare |
1370 | .failure: and ax,ax ; ZF = 0 (at least one will be nonzero) |
1371 | .success: ret |
1372 | |
1373 | ; |
1374 | ; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed |
1375 | ; to by ES:DI; ends on encountering any whitespace. |
1376 | ; |
1377 | ; This verifies that a filename is < FILENAME_MAX characters, |
1378 | ; doesn't contain whitespace, zero-pads the output buffer, |
1379 | ; and removes trailing dots and redundant slashes, |
1380 | ; so "repe cmpsb" can do a compare, and the |
1381 | ; path-searching routine gets a bit of an easier job. |
1382 | ; |
1383 | mangle_name: |
1384 | push bx |
1385 | xor ax,ax |
1386 | mov cx,FILENAME_MAX-1 |
1387 | mov bx,di |
1388 | |
1389 | .mn_loop: |
1390 | lodsb |
1391 | cmp al,' ' ; If control or space, end |
1392 | jna .mn_end |
1393 | cmp al,ah ; Repeated slash? |
1394 | je .mn_skip |
1395 | xor ah,ah |
1396 | cmp al,'/' |
1397 | jne .mn_ok |
1398 | mov ah,al |
1399 | .mn_ok stosb |
1400 | .mn_skip: loop .mn_loop |
1401 | .mn_end: |
1402 | cmp bx,di ; At the beginning of the buffer? |
1403 | jbe .mn_zero |
1404 | cmp byte [di-1],'.' ; Terminal dot? |
1405 | je .mn_kill |
1406 | cmp byte [di-1],'/' ; Terminal slash? |
1407 | jne .mn_zero |
1408 | .mn_kill: dec di ; If so, remove it |
1409 | inc cx |
1410 | jmp short .mn_end |
1411 | .mn_zero: |
1412 | inc cx ; At least one null byte |
1413 | xor ax,ax ; Zero-fill name |
1414 | rep stosb |
1415 | pop bx |
1416 | ret ; Done |
1417 | |
1418 | ; |
1419 | ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled |
1420 | ; filename to the conventional representation. This is needed |
1421 | ; for the BOOT_IMAGE= parameter for the kernel. |
1422 | ; NOTE: A 13-byte buffer is mandatory, even if the string is |
1423 | ; known to be shorter. |
1424 | ; |
1425 | ; DS:SI -> input mangled file name |
1426 | ; ES:DI -> output buffer |
1427 | ; |
1428 | ; On return, DI points to the first byte after the output name, |
1429 | ; which is set to a null byte. |
1430 | ; |
1431 | unmangle_name: call strcpy |
1432 | dec di ; Point to final null byte |
1433 | ret |
1434 | |
1435 | ; |
1436 | ; getfssec: Get multiple clusters from a file, given the file pointer. |
1437 | ; |
1438 | ; On entry: |
1439 | ; ES:BX -> Buffer |
1440 | ; SI -> File pointer |
1441 | ; CX -> Cluster count |
1442 | ; On exit: |
1443 | ; SI -> File pointer (or 0 on EOF) |
1444 | ; CF = 1 -> Hit EOF |
1445 | ; |
1446 | getfssec: |
1447 | TRACER 'F' |
1448 | |
1449 | push ds |
1450 | push cs |
1451 | pop ds ; DS <- CS |
1452 | |
1453 | movzx ecx,cx |
1454 | cmp ecx,[si+file_left] |
1455 | jna .ok_size |
1456 | mov ecx,[si+file_left] |
1457 | .ok_size: |
1458 | |
1459 | mov bp,cx |
1460 | push cx |
1461 | push si |
1462 | mov eax,[si+file_sector] |
1463 | TRACER 'l' |
1464 | call getlinsec |
1465 | xor ecx,ecx |
1466 | pop si |
1467 | pop cx |
1468 | |
1469 | add [si+file_sector],ecx |
1470 | sub [si+file_left],ecx |
1471 | ja .not_eof ; CF = 0 |
1472 | |
1473 | xor ecx,ecx |
1474 | mov [si+file_sector],ecx ; Mark as unused |
1475 | xor si,si |
1476 | stc |
1477 | |
1478 | .not_eof: |
1479 | pop ds |
1480 | TRACER 'f' |
1481 | ret |
1482 | |
1483 | ; ----------------------------------------------------------------------------- |
1484 | ; Common modules |
1485 | ; ----------------------------------------------------------------------------- |
1486 | |
1487 | %include "getc.inc" ; getc et al |
1488 | %include "conio.inc" ; Console I/O |
1489 | %include "parseconfig.inc" ; High-level config file handling |
1490 | %include "parsecmd.inc" ; Low-level config file handling |
1491 | %include "bcopy32.inc" ; 32-bit bcopy |
1492 | %include "loadhigh.inc" ; Load a file into high memory |
1493 | %include "font.inc" ; VGA font stuff |
1494 | %include "graphics.inc" ; VGA graphics |
1495 | %include "highmem.inc" ; High memory sizing |
1496 | %include "strcpy.inc" ; strcpy() |
1497 | %include "rawcon.inc" ; Console I/O w/o using the console functions |
1498 | |
1499 | ; ----------------------------------------------------------------------------- |
1500 | ; Begin data section |
1501 | ; ----------------------------------------------------------------------------- |
1502 | |
1503 | section .data |
1504 | |
1505 | boot_prompt db 'boot: ', 0 |
1506 | wipe_char db BS, ' ', BS, 0 |
1507 | err_notfound db 'Could not find kernel image: ',0 |
1508 | err_notkernel db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0 |
1509 | err_noram db 'It appears your computer has less than ' |
1510 | asciidec dosram_k |
1511 | db 'K of low ("DOS")' |
1512 | db CR, LF |
1513 | db 'RAM. Linux needs at least this amount to boot. If you get' |
1514 | db CR, LF |
1515 | db 'this message in error, hold down the Ctrl key while' |
1516 | db CR, LF |
1517 | db 'booting, and I will take your word for it.', CR, LF, 0 |
1518 | err_badcfg db 'Unknown keyword in config file.', CR, LF, 0 |
1519 | err_noparm db 'Missing parameter in config file.', CR, LF, 0 |
1520 | err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0 |
1521 | err_nohighmem db 'Not enough memory to load specified kernel.', CR, LF, 0 |
1522 | err_highload db CR, LF, 'Kernel transfer failure.', CR, LF, 0 |
1523 | err_oldkernel db 'Cannot load a ramdisk with an old kernel image.' |
1524 | db CR, LF, 0 |
1525 | err_notdos db ': attempted DOS system call', CR, LF, 0 |
1526 | err_comlarge db 'COMBOOT image too large.', CR, LF, 0 |
1527 | err_bssimage db 'BSS images not supported.', CR, LF, 0 |
1528 | err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0 |
1529 | notfound_msg db 'not found', CR, LF, 0 |
1530 | localboot_msg db 'Booting from local disk...', CR, LF, 0 |
1531 | cmdline_msg db 'Command line: ', CR, LF, 0 |
1532 | ready_msg db 'Ready.', CR, LF, 0 |
1533 | trying_msg db 'Trying to load: ', 0 |
1534 | crlfloading_msg db CR, LF ; Fall through |
1535 | loading_msg db 'Loading ', 0 |
1536 | dotdot_msg db '.' |
1537 | dot_msg db '.', 0 |
1538 | fourbs_msg db BS, BS, BS, BS, 0 |
1539 | aborted_msg db ' aborted.', CR, LF, 0 |
1540 | crff_msg db CR, FF, 0 |
1541 | default_str db 'default', 0 |
1542 | default_len equ ($-default_str) |
1543 | boot_dir db '/boot' ; /boot/isolinux |
1544 | isolinux_dir db '/isolinux', 0 |
1545 | ConfigName equ $ |
1546 | isolinux_cfg db 'isolinux.cfg', 0 |
1547 | err_disk_image db 'Cannot load disk image (invalid file)?', CR, LF, 0 |
1548 | |
1549 | %ifdef DEBUG_MESSAGES |
1550 | dbg_rootdir_msg db 'Root directory at LBA = ', 0 |
1551 | dbg_isodir_msg db 'isolinux directory at LBA = ', 0 |
1552 | dbg_config_msg db 'About to load config file...', CR, LF, 0 |
1553 | dbg_configok_msg db 'Configuration file opened...', CR, LF, 0 |
1554 | %endif |
1555 | ; |
1556 | ; Command line options we'd like to take a look at |
1557 | ; |
1558 | ; mem= and vga= are handled as normal 32-bit integer values |
1559 | initrd_cmd db 'initrd=' |
1560 | initrd_cmd_len equ 7 |
1561 | |
1562 | ; |
1563 | ; Config file keyword table |
1564 | ; |
1565 | %include "keywords.inc" |
1566 | |
1567 | ; |
1568 | ; Extensions to search for (in *forward* order). |
1569 | ; |
1570 | align 4, db 0 |
1571 | exten_table: db '.cbt' ; COMBOOT (specific) |
1572 | db '.img' ; Disk image |
1573 | db '.bin' ; CD boot sector |
1574 | db '.com' ; COMBOOT (same as DOS) |
1575 | db '.c32' ; COM32 |
1576 | exten_table_end: |
1577 | dd 0, 0 ; Need 8 null bytes here |
1578 | |
1579 | ; |
1580 | ; Floppy image table |
1581 | ; |
1582 | align 4, db 0 |
1583 | img_table_count equ 3 |
1584 | img_table: |
1585 | dd 1200*1024 ; 1200K floppy |
1586 | db 1 ; Emulation type |
1587 | db 80-1 ; Max cylinder |
1588 | db 15 ; Max sector |
1589 | db 2-1 ; Max head |
1590 | |
1591 | dd 1440*1024 ; 1440K floppy |
1592 | db 2 ; Emulation type |
1593 | db 80-1 ; Max cylinder |
1594 | db 18 ; Max sector |
1595 | db 2-1 ; Max head |
1596 | |
1597 | dd 2880*1024 ; 2880K floppy |
1598 | db 3 ; Emulation type |
1599 | db 80-1 ; Max cylinder |
1600 | db 36 ; Max sector |
1601 | db 2-1 ; Max head |
1602 | |
1603 | ; |
1604 | ; Misc initialized (data) variables |
1605 | ; |
1606 | |
1607 | ; |
1608 | ; Variables that are uninitialized in SYSLINUX but initialized here |
1609 | ; |
1610 | ; **** ISOLINUX:: We may have to make this flexible, based on what the |
1611 | ; **** BIOS expects our "sector size" to be. |
1612 | ; |
1613 | alignb 4, db 0 |
1614 | BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf |
1615 | BufSafeSec dw trackbufsize/SECTOR_SIZE ; = how many sectors? |
1616 | BufSafeBytes dw trackbufsize ; = how many bytes? |
1617 | EndOfGetCBuf dw getcbuf+trackbufsize ; = getcbuf+BufSafeBytes |
1618 | %ifndef DEPEND |
1619 | %if ( trackbufsize % SECTOR_SIZE ) != 0 |
1620 | %error trackbufsize must be a multiple of SECTOR_SIZE |
1621 | %endif |
1622 | %endif |