home *** CD-ROM | disk | FTP | other *** search
/ Chip 2005 August (Alt) / CHIP 2005-08.1.iso / program / guvenlik / syslinux-3.07.exe / isolinux.asm < prev    next >
Encoding:
Assembly Source File  |  2004-12-30  |  41.0 KB  |  1,657 lines

  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. get_fs_structures:
  889.         mov eax,[bi_pvd]
  890.         mov bx,trackbuf
  891.         call getonesec
  892.  
  893.         mov eax,[trackbuf+156+2]
  894.         mov [RootDir+dir_lba],eax
  895.         mov [CurDir+dir_lba],eax
  896. %ifdef DEBUG_MESSAGES
  897.         mov si,dbg_rootdir_msg
  898.         call writemsg
  899.         call writehex8
  900.         call crlf
  901. %endif
  902.         mov eax,[trackbuf+156+10]
  903.         mov [RootDir+dir_len],eax        
  904.         mov [CurDir+dir_len],eax
  905.         add eax,SECTOR_SIZE-1
  906.         shr eax,SECTOR_SHIFT
  907.         mov [RootDir+dir_clust],eax
  908.         mov [CurDir+dir_clust],eax
  909.  
  910.         ; Look for an isolinux directory, and if found,
  911.         ; make it the current directory instead of the root
  912.         ; directory.
  913.         mov di,boot_dir            ; Search for /boot/isolinux
  914.         mov al,02h
  915.         call searchdir_iso
  916.         jnz .found_dir
  917.         mov di,isolinux_dir
  918.         mov al,02h            ; Search for /isolinux
  919.         call searchdir_iso
  920.         jz .no_isolinux_dir
  921. .found_dir:
  922.         mov [CurDir+dir_len],eax
  923.         mov eax,[si+file_left]
  924.         mov [CurDir+dir_clust],eax
  925.         xor eax,eax            ; Free this file pointer entry
  926.         xchg eax,[si+file_sector]
  927.         mov [CurDir+dir_lba],eax
  928. %ifdef DEBUG_MESSAGES
  929.         push si
  930.         mov si,dbg_isodir_msg
  931.         call writemsg
  932.         pop si
  933.         call writehex8
  934.         call crlf
  935. %endif
  936. .no_isolinux_dir:
  937.  
  938. ;
  939. ; Locate the configuration file
  940. ;
  941. load_config:
  942. %ifdef DEBUG_MESSAGES
  943.         mov si,dbg_config_msg
  944.         call writemsg
  945. %endif
  946.  
  947.         mov di,isolinux_cfg
  948.         call open
  949.         jz no_config_file        ; Not found or empty
  950.  
  951. %ifdef DEBUG_MESSAGES
  952.         mov si,dbg_configok_msg
  953.         call writemsg
  954. %endif
  955.  
  956. ;
  957. ; Now we have the config file open.  Parse the config file and
  958. ; run the user interface.
  959. ;
  960. %include "ui.inc"
  961.  
  962. ;
  963. ; Linux kernel loading code is common.
  964. ;
  965. %include "runkernel.inc"
  966.  
  967. ;
  968. ; COMBOOT-loading code
  969. ;
  970. %include "comboot.inc"
  971. %include "com32.inc"
  972. %include "cmdline.inc"
  973.  
  974. ;
  975. ; Boot sector loading code
  976. ;
  977. %include "bootsect.inc"
  978.  
  979. ;
  980. ; Enable disk emulation.  The kind of disk we emulate is dependent on the size of
  981. ; the file: 1200K, 1440K or 2880K floppy, otherwise harddisk.
  982. ;
  983. is_disk_image:
  984.         TRACER CR
  985.         TRACER LF
  986.         TRACER 'D'
  987.         TRACER ':'
  988.  
  989.         shl edx,16
  990.         mov dx,ax            ; Set EDX <- file size
  991.         mov di,img_table
  992.         mov cx,img_table_count
  993.         mov eax,[si+file_sector]    ; Starting LBA of file
  994.         mov [dsp_lba],eax        ; Location of file
  995.         mov byte [dsp_drive], 0        ; 00h floppy, 80h hard disk
  996. .search_table:
  997.         TRACER 't'
  998.         mov eax,[di+4]
  999.         cmp edx,[di]
  1000.         je .type_found
  1001.         add di,8
  1002.         loop .search_table
  1003.  
  1004.         ; Hard disk image.  Need to examine the partition table
  1005.         ; in order to deduce the C/H/S geometry.  Sigh.
  1006. .hard_disk_image:
  1007.         TRACER 'h'
  1008.         cmp edx,512
  1009.         jb .bad_image
  1010.  
  1011.         mov bx,trackbuf
  1012.         mov cx,1            ; Load 1 sector
  1013.         call getfssec
  1014.         
  1015.         cmp word [trackbuf+510],0aa55h    ; Boot signature
  1016.         jne .bad_image        ; Image not bootable
  1017.  
  1018.         mov cx,4            ; 4 partition entries
  1019.         mov di,trackbuf+446        ; Start of partition table
  1020.  
  1021.         xor ax,ax            ; Highest sector(al) head(ah)
  1022.  
  1023. .part_scan:
  1024.         cmp byte [di+4], 0
  1025.         jz .part_loop
  1026.         lea si,[di+1]
  1027.         call .hs_check
  1028.         add si,byte 4
  1029.         call .hs_check
  1030. .part_loop:
  1031.         add di,byte 16
  1032.         loop .part_scan
  1033.         
  1034.         push eax            ; H/S
  1035.         push edx            ; File size
  1036.         mov bl,ah
  1037.         xor bh,bh
  1038.         inc bx                ; # of heads in BX
  1039.         xor ah,ah            ; # of sectors in AX
  1040.         cwde                ; EAX[31:16] <- 0
  1041.         mul bx
  1042.         shl eax,9            ; Convert to bytes
  1043.         ; Now eax contains the number of bytes per cylinder
  1044.         pop ebx                ; File size
  1045.         xor edx,edx
  1046.         div ebx
  1047.         and edx,edx
  1048.         jz .no_remainder
  1049.         inc eax                ; Fractional cylinder...
  1050.         ; Now (e)ax contains the number of cylinders
  1051. .no_remainder:    cmp eax,1024
  1052.         jna .ok_cyl
  1053.         mov ax,1024            ; Max possible #
  1054. .ok_cyl:    dec ax                ; Convert to max cylinder no
  1055.         pop ebx                ; S(bl) H(bh)
  1056.         shl ah,6
  1057.         or bl,ah
  1058.         xchg ax,bx
  1059.         shl eax,16
  1060.         mov ah,bl
  1061.         mov al,4            ; Hard disk boot
  1062.         mov byte [dsp_drive], 80h    ; Drive 80h = hard disk
  1063.  
  1064. .type_found:
  1065.         TRACER 'T'
  1066.         mov bl,[sp_media]
  1067.         and bl,0F0h            ; Copy controller info bits
  1068.         or al,bl
  1069.         mov [dsp_media],al        ; Emulation type
  1070.         shr eax,8
  1071.         mov [dsp_chs],eax        ; C/H/S geometry
  1072.         mov ax,[sp_devspec]        ; Copy device spec
  1073.         mov [dsp_devspec],ax
  1074.         mov al,[sp_controller]        ; Copy controller index
  1075.         mov [dsp_controller],al
  1076.  
  1077.         TRACER 'V'
  1078.         call vgaclearmode        ; Reset video
  1079.  
  1080.         mov ax,4C00h            ; Enable emulation and boot
  1081.         mov si,dspec_packet
  1082.         mov dl,[DriveNo]
  1083.         lss sp,[InitStack]
  1084.         TRACER 'X'
  1085.  
  1086.         int 13h
  1087.  
  1088.         ; If this returns, we have problems
  1089. .bad_image:
  1090.         mov si,err_disk_image
  1091.         call cwritestr
  1092.         jmp enter_command
  1093.  
  1094. ;
  1095. ; Look for the highest seen H/S geometry
  1096. ; We compute cylinders separately
  1097. ;
  1098. .hs_check:
  1099.         mov bl,[si]            ; Head #
  1100.         cmp bl,ah
  1101.         jna .done_track
  1102.         mov ah,bl            ; New highest head #
  1103. .done_track:    mov bl,[si+1]
  1104.         and bl,3Fh            ; Sector #
  1105.         cmp bl,al
  1106.         jna .done_sector
  1107.         mov al,bl
  1108. .done_sector:    ret
  1109.  
  1110. ;
  1111. ; Boot a specified local disk.  AX specifies the BIOS disk number; or
  1112. ; 0xFFFF in case we should execute INT 18h ("next device.")
  1113. ;
  1114. local_boot:
  1115.         call vgaclearmode
  1116.         lss sp,[cs:Stack]        ; Restore stack pointer
  1117.         xor dx,dx
  1118.         mov ds,dx
  1119.         mov es,dx
  1120.         mov fs,dx
  1121.         mov gs,dx
  1122.         mov si,localboot_msg
  1123.         call writestr
  1124.         cmp ax,-1
  1125.         je .int18
  1126.         
  1127.         ; Load boot sector from the specified BIOS device and jump to it.
  1128.         mov dl,al
  1129.         xor dh,dh
  1130.         push dx
  1131.         xor ax,ax            ; Reset drive
  1132.         call xint13
  1133.         mov ax,0201h            ; Read one sector
  1134.         mov cx,0001h            ; C/H/S = 0/0/1 (first sector)
  1135.         mov bx,trackbuf
  1136.         call xint13
  1137.         pop dx
  1138.         cli                ; Abandon hope, ye who enter here
  1139.         mov si,trackbuf
  1140.         mov di,07C00h
  1141.         mov cx,512            ; Probably overkill, but should be safe
  1142.         rep movsd
  1143.         lss sp,[cs:InitStack]
  1144.         jmp 0:07C00h            ; Jump to new boot sector
  1145.  
  1146. .int18:
  1147.         int 18h                ; Hope this does the right thing...
  1148.         jmp kaboom            ; If we returned, oh boy...
  1149.  
  1150. ;
  1151. ; abort_check: let the user abort with <ESC> or <Ctrl-C>
  1152. ;
  1153. abort_check:
  1154.         call pollchar
  1155.         jz ac_ret1
  1156.         pusha
  1157.         call getchar
  1158.         cmp al,27            ; <ESC>
  1159.         je ac_kill
  1160.         cmp al,3            ; <Ctrl-C>
  1161.         jne ac_ret2
  1162. ac_kill:    mov si,aborted_msg
  1163.  
  1164. ;
  1165. ; abort_load: Called by various routines which wants to print a fatal
  1166. ;             error message and return to the command prompt.  Since this
  1167. ;             may happen at just about any stage of the boot process, assume
  1168. ;             our state is messed up, and just reset the segment registers
  1169. ;             and the stack forcibly.
  1170. ;
  1171. ;             SI    = offset (in _text) of error message to print
  1172. ;
  1173. abort_load:
  1174.                 mov ax,cs                       ; Restore CS = DS = ES
  1175.                 mov ds,ax
  1176.                 mov es,ax
  1177.                 cli
  1178.         lss sp,[cs:Stack]        ; Reset the stack
  1179.                 sti
  1180.                 call cwritestr                  ; Expects SI -> error msg
  1181. al_ok:          jmp enter_command               ; Return to command prompt
  1182. ;
  1183. ; End of abort_check
  1184. ;
  1185. ac_ret2:    popa
  1186. ac_ret1:    ret
  1187.  
  1188.  
  1189. ;
  1190. ; searchdir:
  1191. ;
  1192. ;    Open a file
  1193. ;
  1194. ;         On entry:
  1195. ;        DS:DI    = filename
  1196. ;         If successful:
  1197. ;        ZF clear
  1198. ;        SI        = file pointer
  1199. ;        DX:AX or EAX    = file length in bytes
  1200. ;         If unsuccessful
  1201. ;        ZF set
  1202. ;
  1203.  
  1204. ;
  1205. ; searchdir_iso is a special entry point for ISOLINUX only.  In addition
  1206. ; to the above, searchdir_iso passes a file flag mask in AL.  This is useful
  1207. ; for searching for directories.
  1208. ;
  1209. alloc_failure:
  1210.         xor ax,ax            ; ZF <- 1
  1211.         ret
  1212.  
  1213. searchdir:
  1214.         xor al,al
  1215. searchdir_iso:
  1216.         mov [ISOFlags],al
  1217.         TRACER 'S'
  1218.         call allocate_file        ; Temporary file structure for directory
  1219.         jnz alloc_failure
  1220.         push es
  1221.         push ds
  1222.         pop es                ; ES = DS
  1223.         mov si,CurDir
  1224.         cmp byte [di],'/'        ; If filename begins with slash
  1225.         jne .not_rooted
  1226.         inc di                ; Skip leading slash
  1227.         mov si,RootDir            ; Reference root directory instead
  1228. .not_rooted:
  1229.         mov eax,[si+dir_clust]
  1230.         mov [bx+file_left],eax
  1231.         mov eax,[si+dir_lba]
  1232.         mov [bx+file_sector],eax
  1233.         mov edx,[si+dir_len]
  1234.  
  1235. .look_for_slash:
  1236.         mov ax,di
  1237. .scan:
  1238.         mov cl,[di]
  1239.         inc di
  1240.         and cl,cl
  1241.         jz .isfile
  1242.         cmp cl,'/'
  1243.         jne .scan
  1244.         mov [di-1],byte 0        ; Terminate at directory name
  1245.         mov cl,02h            ; Search for directory
  1246.         xchg cl,[ISOFlags]
  1247.  
  1248.         push di                ; Save these...
  1249.         push cx
  1250.  
  1251.         ; Create recursion stack frame...
  1252.         push word .resume        ; Where to "return" to
  1253.         push es
  1254. .isfile:    xchg ax,di
  1255.  
  1256. .getsome:
  1257.         ; Get a chunk of the directory
  1258.         ; This relies on the fact that ISOLINUX doesn't change SI
  1259.         mov si,trackbuf
  1260.         TRACER 'g'
  1261.         pushad
  1262.         xchg bx,si
  1263.         mov cx,[BufSafe]
  1264.         call getfssec
  1265.         popad
  1266.  
  1267. .compare:
  1268.         movzx eax,byte [si]        ; Length of directory entry
  1269.         cmp al,33
  1270.         jb .next_sector
  1271.         TRACER 'c'
  1272.         mov cl,[si+25]
  1273.         xor cl,[ISOFlags]
  1274.         test cl, byte 8Eh        ; Unwanted file attributes!
  1275.         jnz .not_file
  1276.         pusha
  1277.         movzx cx,byte [si+32]        ; File identifier length
  1278.         add si,byte 33            ; File identifier offset
  1279.         TRACER 'i'
  1280.         call iso_compare_names
  1281.         popa
  1282.         je .success
  1283. .not_file:
  1284.         sub edx,eax            ; Decrease bytes left
  1285.         jbe .failure
  1286.         add si,ax            ; Advance pointer
  1287.  
  1288. .check_overrun:
  1289.         ; Did we finish the buffer?
  1290.         cmp si,trackbuf+trackbufsize
  1291.         jb .compare            ; No, keep going
  1292.  
  1293.         jmp short .getsome        ; Get some more directory
  1294.  
  1295. .next_sector:
  1296.         ; Advance to the beginning of next sector
  1297.         lea ax,[si+SECTOR_SIZE-1]
  1298.         and ax,~(SECTOR_SIZE-1)
  1299.         sub ax,si
  1300.         jmp short .not_file        ; We still need to do length checks
  1301.  
  1302. .failure:    xor eax,eax            ; ZF = 1
  1303.         mov [bx+file_sector],eax
  1304.         pop es
  1305.         ret
  1306.  
  1307. .success:
  1308.         mov eax,[si+2]            ; Location of extent
  1309.         mov [bx+file_sector],eax
  1310.         mov eax,[si+10]            ; Data length
  1311.         push eax
  1312.         add eax,SECTOR_SIZE-1
  1313.         shr eax,SECTOR_SHIFT
  1314.         mov [bx+file_left],eax
  1315.         pop eax
  1316.         mov edx,eax
  1317.         shr edx,16
  1318.         and bx,bx            ; ZF = 0
  1319.         mov si,bx
  1320.         pop es
  1321.         ret
  1322.  
  1323. .resume:    ; We get here if we were only doing part of a lookup
  1324.         ; This relies on the fact that .success returns bx == si
  1325.         xchg edx,eax            ; Directory length in edx
  1326.         pop cx                ; Old ISOFlags
  1327.         pop di                ; Next filename pointer
  1328.         mov byte [di-1], '/'        ; Restore slash
  1329.         mov [ISOFlags],cl        ; Restore the flags
  1330.         jz .failure            ; Did we fail?  If so fail for real!
  1331.         jmp .look_for_slash        ; Otherwise, next level
  1332.  
  1333. ;
  1334. ; allocate_file: Allocate a file structure
  1335. ;
  1336. ;        If successful:
  1337. ;          ZF set
  1338. ;          BX = file pointer
  1339. ;        In unsuccessful:
  1340. ;          ZF clear
  1341. ;
  1342. allocate_file:
  1343.         TRACER 'a'
  1344.         push cx
  1345.         mov bx,Files
  1346.         mov cx,MAX_OPEN
  1347. .check:        cmp dword [bx], byte 0
  1348.         je .found
  1349.         add bx,open_file_t_size        ; ZF = 0
  1350.         loop .check
  1351.         ; ZF = 0 if we fell out of the loop
  1352. .found:        pop cx
  1353.         ret
  1354.  
  1355. ;
  1356. ; iso_compare_names: 
  1357. ;    Compare the names DS:SI and DS:DI and report if they are
  1358. ;    equal from an ISO 9660 perspective.  SI is the name from
  1359. ;    the filesystem; CX indicates its length, and ';' terminates.
  1360. ;    DI is expected to end with a null.
  1361. ;
  1362. ;    Note: clobbers AX, CX, SI, DI; assumes DS == ES == base segment
  1363. ;
  1364.  
  1365. iso_compare_names:
  1366.         ; First, terminate and canonicalize input filename
  1367.         push di
  1368.         mov di,ISOFileName
  1369. .canon_loop:    jcxz .canon_end
  1370.         lodsb
  1371.         dec cx
  1372.         cmp al,';'
  1373.         je .canon_end
  1374.         and al,al
  1375.         je .canon_end
  1376.         stosb
  1377.         cmp di,ISOFileNameEnd-1        ; Guard against buffer overrun
  1378.         jb .canon_loop
  1379. .canon_end:
  1380.         cmp di,ISOFileName
  1381.         jbe .canon_done
  1382.         cmp byte [di-1],'.'        ; Remove terminal dots
  1383.         jne .canon_done
  1384.         dec di
  1385.         jmp short .canon_end
  1386. .canon_done:
  1387.         mov [di],byte 0            ; Null-terminate string
  1388.         pop di
  1389.         mov si,ISOFileName
  1390. .compare:
  1391.         lodsb
  1392.         mov ah,[di]
  1393.         inc di
  1394.         and ax,ax
  1395.         jz .success            ; End of string for both
  1396.         and al,al            ; Is either one end of string?
  1397.         jz .failure            ; If so, failure
  1398.         and ah,ah
  1399.         jz .failure
  1400.         or ax,2020h            ; Convert to lower case
  1401.         cmp al,ah
  1402.         je .compare
  1403. .failure:    and ax,ax            ; ZF = 0 (at least one will be nonzero)
  1404. .success:    ret
  1405.  
  1406. ;
  1407. ; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
  1408. ;           to by ES:DI; ends on encountering any whitespace.
  1409. ;
  1410. ;           This verifies that a filename is < FILENAME_MAX characters,
  1411. ;           doesn't contain whitespace, zero-pads the output buffer,
  1412. ;           and removes trailing dots and redundant slashes,
  1413. ;           so "repe cmpsb" can do a compare, and the
  1414. ;           path-searching routine gets a bit of an easier job.
  1415. ;           
  1416. mangle_name:
  1417.         push bx
  1418.         xor ax,ax
  1419.         mov cx,FILENAME_MAX-1
  1420.         mov bx,di
  1421.  
  1422. .mn_loop:
  1423.         lodsb
  1424.         cmp al,' '            ; If control or space, end
  1425.         jna .mn_end
  1426.         cmp al,ah            ; Repeated slash?
  1427.         je .mn_skip
  1428.         xor ah,ah
  1429.         cmp al,'/'
  1430.         jne .mn_ok
  1431.         mov ah,al
  1432. .mn_ok        stosb
  1433. .mn_skip:    loop .mn_loop
  1434. .mn_end:
  1435.         cmp bx,di            ; At the beginning of the buffer?
  1436.         jbe .mn_zero
  1437.         cmp byte [di-1],'.'        ; Terminal dot?
  1438.         je .mn_kill
  1439.         cmp byte [di-1],'/'        ; Terminal slash?
  1440.         jne .mn_zero
  1441. .mn_kill:    dec di                ; If so, remove it
  1442.         inc cx
  1443.         jmp short .mn_end
  1444. .mn_zero:
  1445.         inc cx                ; At least one null byte
  1446.         xor ax,ax            ; Zero-fill name
  1447.         rep stosb
  1448.         pop bx
  1449.         ret                ; Done
  1450.  
  1451. ;
  1452. ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
  1453. ;                filename to the conventional representation.  This is needed
  1454. ;                for the BOOT_IMAGE= parameter for the kernel.
  1455. ;                NOTE: A 13-byte buffer is mandatory, even if the string is
  1456. ;                known to be shorter.
  1457. ;
  1458. ;                DS:SI -> input mangled file name
  1459. ;                ES:DI -> output buffer
  1460. ;
  1461. ;                On return, DI points to the first byte after the output name,
  1462. ;                which is set to a null byte.
  1463. ;
  1464. unmangle_name:    call strcpy
  1465.         dec di                ; Point to final null byte
  1466.         ret
  1467.  
  1468. ;
  1469. ; getfssec: Get multiple clusters from a file, given the file pointer.
  1470. ;
  1471. ;  On entry:
  1472. ;    ES:BX    -> Buffer
  1473. ;    SI    -> File pointer
  1474. ;    CX    -> Cluster count
  1475. ;  On exit:
  1476. ;    SI    -> File pointer (or 0 on EOF)
  1477. ;    CF = 1    -> Hit EOF
  1478. ;
  1479. getfssec:
  1480.         TRACER 'F'
  1481.  
  1482.         push ds
  1483.         push cs
  1484.         pop ds                ; DS <- CS
  1485.  
  1486.         movzx ecx,cx
  1487.         cmp ecx,[si+file_left]
  1488.         jna .ok_size
  1489.         mov ecx,[si+file_left]
  1490. .ok_size:
  1491.  
  1492.         mov bp,cx
  1493.         push cx
  1494.         push si
  1495.         mov eax,[si+file_sector]
  1496.         TRACER 'l'
  1497.         call getlinsec
  1498.         xor ecx,ecx
  1499.         pop si
  1500.         pop cx
  1501.  
  1502.         add [si+file_sector],ecx
  1503.         sub [si+file_left],ecx
  1504.         ja .not_eof            ; CF = 0
  1505.  
  1506.         xor ecx,ecx
  1507.         mov [si+file_sector],ecx    ; Mark as unused
  1508.         xor si,si
  1509.         stc
  1510.  
  1511. .not_eof:
  1512.         pop ds
  1513.         TRACER 'f'
  1514.         ret
  1515.  
  1516. ; -----------------------------------------------------------------------------
  1517. ;  Common modules
  1518. ; -----------------------------------------------------------------------------
  1519.  
  1520. %include "getc.inc"        ; getc et al
  1521. %include "conio.inc"        ; Console I/O
  1522. %include "parseconfig.inc"    ; High-level config file handling
  1523. %include "parsecmd.inc"        ; Low-level config file handling
  1524. %include "bcopy32.inc"        ; 32-bit bcopy
  1525. %include "loadhigh.inc"        ; Load a file into high memory
  1526. %include "font.inc"        ; VGA font stuff
  1527. %include "graphics.inc"        ; VGA graphics
  1528. %include "highmem.inc"        ; High memory sizing
  1529. %include "strcpy.inc"        ; strcpy()
  1530. %include "rawcon.inc"        ; Console I/O w/o using the console functions
  1531.  
  1532. ; -----------------------------------------------------------------------------
  1533. ;  Begin data section
  1534. ; -----------------------------------------------------------------------------
  1535.  
  1536.         section .data
  1537.  
  1538. boot_prompt    db 'boot: ', 0
  1539. wipe_char    db BS, ' ', BS, 0
  1540. err_notfound    db 'Could not find kernel image: ',0
  1541. err_notkernel    db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0
  1542. err_noram    db 'It appears your computer has less than '
  1543.         asciidec dosram_k
  1544.         db 'K of low ("DOS")'
  1545.         db CR, LF
  1546.         db 'RAM.  Linux needs at least this amount to boot.  If you get'
  1547.         db CR, LF
  1548.         db 'this message in error, hold down the Ctrl key while'
  1549.         db CR, LF
  1550.         db 'booting, and I will take your word for it.', CR, LF, 0
  1551. err_badcfg      db 'Unknown keyword in config file.', CR, LF, 0
  1552. err_noparm      db 'Missing parameter in config file.', CR, LF, 0
  1553. err_noinitrd    db CR, LF, 'Could not find ramdisk image: ', 0
  1554. err_nohighmem   db 'Not enough memory to load specified kernel.', CR, LF, 0
  1555. err_highload    db CR, LF, 'Kernel transfer failure.', CR, LF, 0
  1556. err_oldkernel   db 'Cannot load a ramdisk with an old kernel image.'
  1557.                 db CR, LF, 0
  1558. err_notdos    db ': attempted DOS system call', CR, LF, 0
  1559. err_comlarge    db 'COMBOOT image too large.', CR, LF, 0
  1560. err_bssimage    db 'BSS images not supported.', CR, LF, 0
  1561. err_a20        db CR, LF, 'A20 gate not responding!', CR, LF, 0
  1562. notfound_msg    db 'not found', CR, LF, 0
  1563. localboot_msg    db 'Booting from local disk...', CR, LF, 0
  1564. cmdline_msg    db 'Command line: ', CR, LF, 0
  1565. ready_msg    db 'Ready.', CR, LF, 0
  1566. trying_msg    db 'Trying to load: ', 0
  1567. crlfloading_msg    db CR, LF            ; Fall through
  1568. loading_msg     db 'Loading ', 0
  1569. dotdot_msg      db '.'
  1570. dot_msg         db '.', 0
  1571. fourbs_msg    db BS, BS, BS, BS, 0
  1572. aborted_msg    db ' aborted.', CR, LF, 0
  1573. crff_msg    db CR, FF, 0
  1574. default_str    db 'default', 0
  1575. default_len    equ ($-default_str)
  1576. boot_dir    db '/boot'            ; /boot/isolinux
  1577. isolinux_dir    db '/isolinux', 0
  1578. ConfigName    equ $
  1579. isolinux_cfg    db 'isolinux.cfg', 0
  1580. err_disk_image    db 'Cannot load disk image (invalid file)?', CR, LF, 0
  1581.  
  1582. %ifdef DEBUG_MESSAGES
  1583. dbg_rootdir_msg    db 'Root directory at LBA = ', 0
  1584. dbg_isodir_msg    db 'isolinux directory at LBA = ', 0
  1585. dbg_config_msg    db 'About to load config file...', CR, LF, 0
  1586. dbg_configok_msg    db 'Configuration file opened...', CR, LF, 0
  1587. %endif
  1588. ;
  1589. ; Command line options we'd like to take a look at
  1590. ;
  1591. ; mem= and vga= are handled as normal 32-bit integer values
  1592. initrd_cmd    db 'initrd='
  1593. initrd_cmd_len    equ 7
  1594.  
  1595. ;
  1596. ; Config file keyword table
  1597. ;
  1598. %include "keywords.inc"
  1599.  
  1600. ;
  1601. ; Extensions to search for (in *forward* order).
  1602. ;
  1603.         align 4, db 0
  1604. exten_table:    db '.cbt'        ; COMBOOT (specific)
  1605.         db '.img'        ; Disk image
  1606.         db '.bin'        ; CD boot sector
  1607.         db '.com'        ; COMBOOT (same as DOS)
  1608.         db '.c32'        ; COM32
  1609. exten_table_end:
  1610.         dd 0, 0            ; Need 8 null bytes here
  1611.  
  1612. ;
  1613. ; Floppy image table
  1614. ;
  1615.         align 4, db 0
  1616. img_table_count    equ 3
  1617. img_table:
  1618.         dd 1200*1024        ; 1200K floppy
  1619.         db 1            ; Emulation type
  1620.         db 80-1            ; Max cylinder
  1621.         db 15            ; Max sector
  1622.         db 2-1            ; Max head
  1623.  
  1624.         dd 1440*1024        ; 1440K floppy
  1625.         db 2            ; Emulation type
  1626.         db 80-1            ; Max cylinder
  1627.         db 18            ; Max sector
  1628.         db 2-1            ; Max head
  1629.  
  1630.         dd 2880*1024        ; 2880K floppy
  1631.         db 3            ; Emulation type
  1632.         db 80-1            ; Max cylinder
  1633.         db 36            ; Max sector
  1634.         db 2-1            ; Max head
  1635.  
  1636. ;
  1637. ; Misc initialized (data) variables
  1638. ;
  1639.  
  1640. ;
  1641. ; Variables that are uninitialized in SYSLINUX but initialized here
  1642. ;
  1643. ; **** ISOLINUX:: We may have to make this flexible, based on what the
  1644. ; **** BIOS expects our "sector size" to be.
  1645. ;
  1646.         alignb 4, db 0
  1647. BufSafe        dw trackbufsize/SECTOR_SIZE    ; Clusters we can load into trackbuf
  1648. BufSafeSec    dw trackbufsize/SECTOR_SIZE    ; = how many sectors?
  1649. BufSafeBytes    dw trackbufsize        ; = how many bytes?
  1650. EndOfGetCBuf    dw getcbuf+trackbufsize    ; = getcbuf+BufSafeBytes
  1651. %ifndef DEPEND
  1652. %if ( trackbufsize % SECTOR_SIZE ) != 0
  1653. %error trackbufsize must be a multiple of SECTOR_SIZE
  1654. %endif
  1655. %endif
  1656.