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