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