Magellan Linux

Contents of /trunk/mkinitrd-magellan/isolinux/isolinux.asm

Parent Directory Parent Directory | Revision Log Revision Log


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