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