1                                  ; -*- fundamental -*- (asm-mode sucks)
    2                                  ; $Id: ldlinux.asm,v 1.52 1999/06/15 03:19:07 hpa Exp $
    3                                  ; ****************************************************************************
    4                                  ;
    5                                  ;  ldlinux.asm
    6                                  ;
    7                                  ;  A program to boot Linux kernels off an MS-DOS formatted floppy disk.  This
    8                                  ;  functionality is good to have for installation floppies, where it may
    9                                  ;  be hard to find a functional Linux system to run LILO off.
   10                                  ;
   11                                  ;  This program allows manipulation of the disk to take place entirely
   12                                  ;  from MS-LOSS, and can be especially useful in conjunction with the
   13                                  ;  umsdos filesystem.
   14                                  ;
   15                                  ;  This file is loaded in stages; first the boot sector at offset 7C00h,
   16                                  ;  then the first sector (cluster, really, but we can only assume 1 sector)
   17                                  ;  of LDLINUX.SYS at 7E00h and finally the remainder of LDLINUX.SYS at 8000h.
   18                                  ;
   19                                  ;   Copyright (C) 1994-1999  H. Peter Anvin
   20                                  ;
   21                                  ;  This program is free software; you can redistribute it and/or modify
   22                                  ;  it under the terms of the GNU General Public License as published by
   23                                  ;  the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
   24                                  ;  USA; either version 2 of the License, or (at your option) any later
   25                                  ;  version; incorporated herein by reference.
   26                                  ;
   27                                  ; ****************************************************************************
   28
   29                                  ;
   30                                  ; Some semi-configurable constants... change on your own risk.  Most are imposed
   31                                  ; by the kernel.
   32                                  ;
   33                                  max_cmd_len     equ 255                 ; Must be odd; 255 is the kernel limit
   34                                  retry_count     equ 6                   ; How patient are we with the disk?
   35                                  HIGHMEM_MAX     equ 038000000h          ; Highest address for an initrd
   36                                  DEFAULT_BAUD    equ 9600                ; Default baud rate for serial port
   37                                  BAUD_DIVISOR    equ 115200              ; Serial port parameter
   38                                  ;
   39                                  ; Should be updated with every release to avoid bootsector/SYS file mismatch
   40                                  ;
   41                                  %define version_str     VERSION         ; Must be 4 characters long!
   42                                  %define date            DATE_STR        ; Defined from the Makefile
   43                                  %define year            '1999'
   44                                  ;
   45                                  ; Debgging stuff
   46                                  ;
   47                                  ; %define debug 1                       ; Uncomment to enable debugging
   48                                  ;
   49                                  ; ID for SYSLINUX (reported to kernel)
   50                                  ;
   51                                  syslinux_id     equ 031h                ; SYSLINUX (3) version 1.x (1)
   52                                  ;
   53                                  ; Segments used by Linux
   54                                  ;
   55                                  real_mode_seg   equ 9000h
   56                                                  struc real_mode_seg_t
   57 00000000 <res 00000020>                          resb 20h-($-$$)         ; org 20h
   58 00000020 <res 00000002>          kern_cmd_magic  resw 1                  ; Magic # for command line
   59 00000022 <res 00000002>          kern_cmd_offset resw 1                  ; Offset for kernel command line
   60 00000024 <res 000001CD>                          resb 497-($-$$)         ; org 497d
   61 000001F1 <res 00000001>          bs_setupsecs    resb 1                  ; Sectors for setup code (0 -> 4)
   62 000001F2 <res 00000002>          bs_rootflags    resw 1                  ; Root readonly flag
   63 000001F4 <res 00000002>          bs_syssize      resw 1
   64 000001F6 <res 00000002>          bs_swapdev      resw 1                  ; Swap device (obsolete)
   65 000001F8 <res 00000002>          bs_ramsize      resw 1                  ; Ramdisk flags, formerly ramdisk size
   66 000001FA <res 00000002>          bs_vidmode      resw 1                  ; Video mode
   67 000001FC <res 00000002>          bs_rootdev      resw 1                  ; Root device
   68 000001FE <res 00000002>          bs_bootsign     resw 1                  ; Boot sector signature (0AA55h)
   69 00000200 <res 00000001>          su_jump         resb 1                  ; 0EBh
   70 00000201 <res 00000001>          su_jump2        resb 1
   71 00000202 <res 00000004>          su_header       resd 1                  ; New setup code: header
   72 00000206 <res 00000002>          su_version      resw 1                  ; See linux/arch/i386/boot/setup.S
   73 00000208 <res 00000002>          su_switch       resw 1
   74 0000020A <res 00000002>          su_setupseg     resw 1
   75 0000020C <res 00000002>          su_startsys     resw 1
   76 0000020E <res 00000002>          su_kver         resw 1                  ; Kernel version pointer
   77 00000210 <res 00000001>          su_loader       resb 1                  ; Loader ID
   78 00000211 <res 00000001>          su_loadflags    resb 1                  ; Load high flag
   79 00000212 <res 00000002>          su_movesize     resw 1
   80 00000214 <res 00000004>          su_code32start  resd 1                  ; Start of code loaded high
   81 00000218 <res 00000004>          su_ramdiskat    resd 1                  ; Start of initial ramdisk
   82                                  su_ramdisklen   equ $                   ; Length of initial ramdisk
   83 0000021C <res 00000002>          su_ramdisklen1  resw 1
   84 0000021E <res 00000002>          su_ramdisklen2  resw 1
   85 00000220 <res 00000002>          su_bsklugeoffs  resw 1
   86 00000222 <res 00000002>          su_bsklugeseg   resw 1
   87 00000224 <res 00000002>          su_heapend      resw 1
   88 00000226 <res 00007DCE>                          resb (8000h-12)-($-$$)  ; Were bootsect.S puts it...
   89                                  linux_stack     equ $
   90                                  linux_fdctab    equ $
   91 00007FF4 <res 0000000C>                          resb 8000h-($-$$)
   92                                  cmd_line_here   equ $                   ; Should be out of the way
   93                                                  endstruc
   94
   95                                  setup_seg       equ 9020h
   96                                                  struc setup_seg_t
   97                                                  org 0h                  ; as 9020:0000, not 9000:0200
   98                                  setup_entry     equ $
   99                                                  endstruc
  100
  101                                  ;
  102                                  ; Magic number of su_header field
  103                                  ;
  104                                  HEADER_ID       equ 'HdrS'              ; HdrS (in littleendian hex)
  105                                  ;
  106                                  ; Flags for the su_loadflags field
  107                                  ;
  108                                  LOAD_HIGH       equ 01h                 ; Large kernel, load high
  109                                  CAN_USE_HEAP    equ 80h                 ; Boot loader reports heap size
  110                                  ;
  111                                  ; The following structure is used for "virtual kernels"; i.e. LILO-style
  112                                  ; option labels.  The options we permit here are `kernel' and `append
  113                                  ; Since there is no room in the bottom 64K for all of these, we
  114                                  ; stick them at 8000:0000 and copy them down before we need them.
  115                                  ;
  116                                  ; Note: this structure can be added to, but it must
  117                                  ;
  118                                  %define vk_power        7               ; log2(max number of vkernels)
  119                                  %define max_vk          (1 << vk_power) ; Maximum number of vkernels
  120                                  %define vk_shift        (16-vk_power)   ; Number of bits to shift
  121                                  %define vk_size         (1 << vk_shift) ; Size of a vkernel buffer
  122
  123                                                  struc vkernel
  124 00000000 <res 0000000B>          vk_vname:       resb 11                 ; Virtual name **MUST BE FIRST!**
  125 0000000B <res 0000000B>          vk_rname:       resb 11                 ; Real name
  126 00000016 <res 00000002>          vk_appendlen:   resw 1
  127                                                  alignb 4
  128 00000018 <res 00000100>          vk_append:      resb max_cmd_len+1      ; Command line
  129                                                  alignb 4
  130                                  vk_end:         equ $                   ; Should be <= vk_size
  131                                                  endstruc
  132
  133                                  %if (vk_end > vk_size) || (vk_size*max_vk > 65536)
  134                                  %error "Too many vkernels defined, reduce vk_power"
  135                                  %endif
  136
  137                                  ;
  138                                  ; Segment assignments in the bottom 640K
  139                                  ; 0000h - main code/data segment (and BIOS segment)
  140                                  ; 9000h - real_mode_seg
  141                                  ;
  142                                  vk_seg          equ 8000h               ; This is where we stick'em
  143                                  xfer_buf_seg    equ 7000h               ; Bounce buffer for I/O to high mem
  144                                  fat_seg         equ 5000h               ; 128K area for FAT (2x64K)
  145                                  comboot_seg     equ 2000h               ; COMBOOT image loading zone
  146
  147                                  ;
  148                                  ; For our convenience: define macros for jump-over-unconditinal jumps
  149                                  ;
  150                                  %macro  jmpz    1
  151                                          jnz %%skip
  152                                          jmp %1
  153                                  %%skip:
  154                                  %endmacro
  155
  156                                  %macro  jmpnz   1
  157                                          jz %%skip
  158                                          jmp %1
  159                                  %%skip:
  160                                  %endmacro
  161
  162                                  %macro  jmpe    1
  163                                          jne %%skip
  164                                          jmp %1
  165                                  %%skip:
  166                                  %endmacro
  167
  168                                  %macro  jmpne   1
  169                                          je %%skip
  170                                          jmp %1
  171                                  %%skip:
  172                                  %endmacro
  173
  174                                  %macro  jmpc    1
  175                                          jnc %%skip
  176                                          jmp %1
  177                                  %%skip:
  178                                  %endmacro
  179
  180                                  %macro  jmpnc   1
  181                                          jc %%skip
  182                                          jmp %1
  183                                  %%skip:
  184                                  %endmacro
  185
  186                                  %macro  jmpb    1
  187                                          jnb %%skip
  188                                          jmp %1
  189                                  %%skip:
  190                                  %endmacro
  191
  192                                  %macro  jmpnb   1
  193                                          jb %%skip
  194                                          jmp %1
  195                                  %%skip:
  196                                  %endmacro
  197
  198                                  ;
  199                                  ; Macros similar to res[bwd], but which works in the code segment (after
  200                                  ; section .text)
  201                                  ;
  202                                  %macro  zb      1
  203                                          times %1 db 0
  204                                  %endmacro
  205
  206                                  %macro  zw      1
  207                                          times %1 dw 0
  208                                  %endmacro
  209
  210                                  %macro  zd      1
  211                                          times %1 dd 0
  212                                  %endmacro
  213
  214                                  ; ---------------------------------------------------------------------------
  215                                  ;   BEGIN THE BIOS/CODE/DATA SEGMENT
  216                                  ; ---------------------------------------------------------------------------
  217                                                  absolute 4*1Eh          ; In the interrupt table
  218                                  fdctab          equ $
  219 00000078 <res 00000002>          fdctab1         resw 1
  220 0000007A <res 00000002>          fdctab2         resw 1
  221
  222                                  %ifdef debug
  223                                                  org 0100h
  224                                  ..start:
  225                                  ;
  226                                  ; Hook for debugger stuff.  This gets automatically removed when
  227                                  ; generating the real thing.
  228                                  ;
  229                                  ; Initialize the registers for debugger operation
  230                                  ;
  231                                                  cli
  232                                                  mov ax,cs
  233                                                  mov ds,ax
  234                                                  mov es,ax
  235                                                  mov ss,ax
  236                                                  mov sp,StackBuf
  237                                                  sti
  238                                                  cld
  239                                  ;
  240                                  ; Load the actual boot sector so we can copy the data block
  241                                  ;
  242                                                  xor ax,ax               ; Reset floppy
  243                                                  xor dx,dx
  244                                                  int 13h
  245                                                  mov cx,6                ; Retry count...
  246                                  debug_tryloop:  push cx
  247                                                  mov bx,trackbuf
  248                                                  mov cx,0001h
  249                                                  xor dx,dx
  250                                                  mov ax,0201h
  251                                                  int 13h
  252                                                  pop cx
  253                                                  jnc debug_okay
  254                                                  loop debug_tryloop
  255                                                  int 3                   ; Halt! (Breakpoint)
  256                                  debug_okay:     mov si,trackbuf+0bh
  257                                                  mov di,bsBytesPerSec
  258                                                  mov cx,33h
  259                                                  rep movsb
  260                                  ;
  261                                  ; Save bogus "BIOS floppy block" info to the stack in case we hit kaboom
  262                                  ;
  263                                                  push si
  264                                                  push si
  265                                                  push si                 ; Writing to the trackbuf is harmless
  266                                  ;
  267                                  ; Copy the BIOS data area
  268                                  ;
  269                                                  push ds
  270                                                  xor ax,ax
  271                                                  mov ds,ax
  272                                                  mov si,0400h
  273                                                  mov di,si
  274                                                  mov cx,0100h
  275                                                  rep movsw
  276                                                  pop ds
  277                                  ;
  278                                  ;
  279                                  ; A NOP where we can breakpoint, then jump into the code *after*
  280                                  ; the segment register initialization section
  281                                  ;
  282                                                  nop
  283                                                  jmp debugentrypt
  284                                  %endif
  285                                                  absolute 0400h
  286 00000400 <res 00000008>          serial_base     resw 4                  ; Base addresses for 4 serial ports
  287
  288                                                  absolute 0484h
  289 00000484 <res 00000001>          BIOS_vidrows    resb 1                  ; Number of screen rows
  290
  291                                  ;
  292                                  ; Memory below this point is reserved for the BIOS and the MBR
  293                                  ;
  294                                                  absolute 1000h
  295                                  trackbuf        equ $                   ; Track buffer goes here
  296                                  trackbufsize    equ 16384               ; Safe size of track buffer
  297                                  ;               trackbuf ends at 5000h
  298
  299                                                  absolute 6000h          ; Here we keep our BSS stuff
  300                                  StackBuf        equ $                   ; Start the stack here (grow down - 4K)
  301 00006000 <res 00000200>          VKernelBuf:     resb vk_size            ; "Current" vkernel
  302                                                  alignb 4
  303 00006200 <res 00000100>          AppendBuf       resb max_cmd_len+1      ; append=
  304 00006300 <res 00000100>          KbdMap          resb 256                ; Keyboard map
  305 00006400 <res 000000A0>          FKeyName        resb 10*16              ; File names for F-key help
  306 000064A0 <res 00000010>          NumBuf          resb 16                 ; Buffer to load number
  307                                  NumBufEnd       equ NumBuf+15           ; Pointer to last byte in NumBuf
  308                                                  alignb 4
  309 000064B0 <res 00000010>          PartInfo        resb 16                 ; Partition table entry
  310 000064C0 <res 00000004>          InitRDat        resd 1                  ; Load address (linear) for initrd
  311 000064C4 <res 00000004>          HiLoadAddr      resd 1                  ; Address pointer for high load loop
  312 000064C8 <res 00000004>          HighMemSize     resd 1                  ; End of memory pointer (bytes)
  313 000064CC <res 00000004>          KernelSize      resd 1                  ; Size of kernel (bytes)
  314 000064D0 <res 0000000C>          KernelName      resb 12                 ; Mangled name for kernel
  315                                                                          ; (note the spare byte after!)
  316                                  RootDir         equ $                   ; Location of root directory
  317 000064DC <res 00000002>          RootDir1        resw 1
  318 000064DE <res 00000002>          RootDir2        resw 1
  319                                  DataArea        equ $                   ; Location of data area
  320 000064E0 <res 00000002>          DataArea1       resw 1
  321 000064E2 <res 00000002>          DataArea2       resw 1
  322                                  FBytes          equ $                   ; Used by open/getc
  323 000064E4 <res 00000002>          FBytes1         resw 1
  324 000064E6 <res 00000002>          FBytes2         resw 1
  325 000064E8 <res 00000002>          RootDirSize     resw 1                  ; Root dir size in sectors
  326 000064EA <res 00000002>          DirScanCtr      resw 1                  ; Used while searching directory
  327 000064EC <res 00000002>          DirBlocksLeft   resw 1                  ; Ditto
  328 000064EE <res 00000002>          EndofDirSec     resw 1                  ; = trackbuf+bsBytesPerSec-31
  329 000064F0 <res 00000002>          RunLinClust     resw 1                  ; Cluster # for LDLINUX.SYS
  330 000064F2 <res 00000002>          ClustSize       resw 1                  ; Bytes/cluster
  331 000064F4 <res 00000002>          SecPerClust     resw 1                  ; Same as bsSecPerClust, but a word
  332 000064F6 <res 00000002>          NextCluster     resw 1                  ; Pointer to "nextcluster" routine
  333 000064F8 <res 00000002>          BufSafe         resw 1                  ; Clusters we can load into trackbuf
  334 000064FA <res 00000002>          BufSafeSec      resw 1                  ; = how many sectors?
  335 000064FC <res 00000002>          BufSafeBytes    resw 1                  ; = how many bytes?
  336 000064FE <res 00000002>          EndOfGetCBuf    resw 1                  ; = getcbuf+BufSafeBytes
  337 00006500 <res 00000002>          KernelClust     resw 1                  ; Kernel size in clusters
  338 00006502 <res 00000002>          InitRDClust     resw 1                  ; Ramdisk size in clusters
  339 00006504 <res 00000002>          ClustPerMoby    resw 1                  ; Clusters per 64K
  340 00006506 <res 00000002>          FClust          resw 1                  ; Number of clusters in open/getc file
  341 00006508 <res 00000002>          FNextClust      resw 1                  ; Pointer to next cluster in d:o
  342 0000650A <res 00000002>          FPtr            resw 1                  ; Pointer to next char in buffer
  343 0000650C <res 00000002>          CmdOptPtr       resw 1                  ; Pointer to first option on cmd line
  344 0000650E <res 00000002>          KernelCNameLen  resw 1                  ; Length of unmangled kernel name
  345 00006510 <res 00000002>          InitRDCNameLen  resw 1                  ; Length of unmangled initrd name
  346 00006512 <res 00000002>          NextCharJump    resw 1                  ; Routine to interpret next print char
  347 00006514 <res 00000002>          SetupSecs       resw 1                  ; Number of setup sectors
  348 00006516 <res 00000002>          SavedSP         resw 1                  ; Our SP while running a COMBOOT image
  349 00006518 <res 00000002>          A20Test         resw 1                  ; Counter for testing status of A20
  350                                  TextAttrBX      equ $
  351 0000651A <res 00000001>          TextAttribute   resb 1                  ; Text attribute for message file
  352 0000651B <res 00000001>          TextPage        resb 1                  ; Active display page
  353                                  CursorDX        equ $
  354 0000651C <res 00000001>          CursorCol       resb 1                  ; Cursor column for message file
  355 0000651D <res 00000001>          CursorRow       resb 1                  ; Cursor row for message file
  356                                  ScreenSize      equ $
  357 0000651E <res 00000001>          VidCols         resb 1                  ; Columns on screen-1
  358 0000651F <res 00000001>          VidRows         resb 1                  ; Rows on screen-1
  359 00006520 <res 00000001>          RetryCount      resb 1                  ; Used for disk access retries
  360 00006521 <res 00000001>          KbdFlags        resb 1                  ; Check for keyboard escapes
  361 00006522 <res 00000001>          LoadFlags       resb 1                  ; Loadflags from kernel
  362 00006523 <res 00000001>          A20Tries        resb 1                  ; Times until giving up on A20
  363 00006524 <res 00000001>          FuncFlag        resb 1                  ; == 1 if <Ctrl-F> pressed
  364 00006525 <res 0000000B>          MNameBuf        resb 11                 ; Generic mangled file name buffer
  365 00006530 <res 0000000B>          InitRD          resb 11                 ; initrd= mangled name
  366 0000653B <res 0000000D>          KernelCName     resb 13                 ; Unmangled kernel name
  367 00006548 <res 0000000D>          InitRDCName     resb 13                 ; Unmangled initrd name
  368
  369                                                  section .text
  370                                                  org 7C00h
  371                                  ;
  372                                  ; Primary entry point.  Tempting as though it may be, we can't put the
  373                                  ; initial "cli" here; the jmp opcode in the first byte is part of the
  374                                  ; "magic number" (using the term very loosely) for the DOS superblock.
  375                                  ;
  376                                  bootsec         equ $
  377 00000000 EB3C                                    jmp short start         ; 2 bytes
  378 00000002 90                                      nop                     ; 1 byte
  379                                  ;
  380                                  ; "Superblock" follows -- it's in the boot sector, so it's already
  381                                  ; loaded and ready for us
  382                                  ;
  383 00000003 5359534C494E5558        bsOemName       db 'SYSLINUX'           ; The SYS command sets this, so...
  384                                  superblock      equ $
  385                                  bsBytesPerSec   zw 1
  386                              <1> bsBytesPerSec   :
  387 0000000B 0000                <1>         times %1 dw 0
  388                                  bsSecPerClust   zb 1
  389                              <1> bsSecPerClust   :
  390 0000000D 00                  <1>         times %1 db 0
  391                                  bsResSectors    zw 1
  392                              <1> bsResSectors    :
  393 0000000E 0000                <1>         times %1 dw 0
  394                                  bsFATs          zb 1
  395                              <1> bsFATs          :
  396 00000010 00                  <1>         times %1 db 0
  397                                  bsRootDirEnts   zw 1
  398                              <1> bsRootDirEnts   :
  399 00000011 0000                <1>         times %1 dw 0
  400                                  bsSectors       zw 1
  401                              <1> bsSectors       :
  402 00000013 0000                <1>         times %1 dw 0
  403                                  bsMedia         zb 1
  404                              <1> bsMedia         :
  405 00000015 00                  <1>         times %1 db 0
  406                                  bsFATsecs       zw 1
  407                              <1> bsFATsecs       :
  408 00000016 0000                <1>         times %1 dw 0
  409                                  bsSecPerTrack   zw 1
  410                              <1> bsSecPerTrack   :
  411 00000018 0000                <1>         times %1 dw 0
  412                                  bsHeads         zw 1
  413                              <1> bsHeads         :
  414 0000001A 0000                <1>         times %1 dw 0
  415                                  bsHiddenSecs    equ $
  416                                  bsHidden1       zw 1
  417                              <1> bsHidden1       :
  418 0000001C 0000                <1>         times %1 dw 0
  419                                  bsHidden2       zw 1
  420                              <1> bsHidden2       :
  421 0000001E 0000                <1>         times %1 dw 0
  422                                  bsHugeSectors   equ $
  423                                  bsHugeSec1      zw 1
  424                              <1> bsHugeSec1      :
  425 00000020 0000                <1>         times %1 dw 0
  426                                  bsHugeSec2      zw 1
  427                              <1> bsHugeSec2      :
  428 00000022 0000                <1>         times %1 dw 0
  429                                  bsDriveNumber   zb 1
  430                              <1> bsDriveNumber   :
  431 00000024 00                  <1>         times %1 db 0
  432                                  bsReserved1     zb 1
  433                              <1> bsReserved1     :
  434 00000025 00                  <1>         times %1 db 0
  435                                  bsBootSignature zb 1                    ; 29h if the following fields exist
  436                              <1> bsBootSignature :
  437 00000026 00                  <1>         times %1 db 0
  438                                  bsVolumeID      zd 1
  439                              <1> bsVolumeID      :
  440 00000027 00000000            <1>         times %1 dd 0
  441                                  bsVolumeLabel   zb 11
  442                              <1> bsVolumeLabel   :
  443 0000002B 00<rept>            <1>         times %1 db 0
  444                                  bsFileSysType   zb 8                    ; Must be FAT12 for this version
  445                              <1> bsFileSysType   :
  446 00000036 00<rept>            <1>         times %1 db 0
  447                                  superblock_len  equ $-superblock
  448                                  ;
  449                                  ; Note we don't check the constraints above now; we did that at install
  450                                  ; time (we hope!)
  451                                  ;
  452
  453                                  ;floppy_table   equ $                   ; No sense in wasting memory, overwrite start
  454
  455                                  start:
  456 0000003E FA                                      cli                     ; No interrupts yet, please
  457 0000003F FC                                      cld                     ; Copy upwards
  458                                  ;
  459                                  ; Set up the stack
  460                                  ;
  461 00000040 31C9                                    xor cx,cx
  462 00000042 8ED1                                    mov ss,cx
  463 00000044 BC0060                                  mov sp,StackBuf         ; Just below BSS
  464 00000047 8EC1                                    mov es,cx
  465                                  ;
  466                                  ; DS:SI may contain a partition table entry.  Preserve it for us.
  467                                  ;
  468 00000049 B108                                    mov cl,8                ; Save partition info (CH == 0)
  469 0000004B BFB064                                  mov di,PartInfo
  470 0000004E F3A5                                    rep movsw
  471                                  ;
  472                                  ; Now sautee the BIOS floppy info block to that it will support decent-
  473                                  ; size transfers; the floppy block is 11 bytes and is stored in the
  474                                  ; INT 1Eh vector (brilliant waste of resources, eh?)
  475                                  ;
  476                                  ; Of course, if BIOSes had been properly programmed, we wouldn't have
  477                                  ; had to waste precious boot sector space with this code.
  478                                  ;
  479                                  ; This code no longer fits.  Hope that noone really needs it anymore.
  480                                  ; (If so, it needs serious updating.)  In fact, some indications is that
  481                                  ; this code does more harm than good with all the new kinds of drives and
  482                                  ; media.
  483                                  ;
  484                                  %ifdef SUPPORT_REALLY_BROKEN_BIOSES
  485                                                  lds si,[ss:fdctab]      ; DS:SI -> original
  486                                                  push ds                 ; Save on stack in case
  487                                                  push si                 ; we have to bail
  488                                                  push bx
  489                                                  mov cx,6                ; 12 bytes
  490                                                  mov di,floppy_table
  491                                                  push di
  492                                                  cld
  493                                                  rep movsw               ; Faster to move words
  494                                                  pop di
  495                                                  mov ds,ax               ; Now we can point DS to here, too
  496                                                  mov cl,[bsSecPerTrack]  ; Patch the sector count
  497                                                  mov [di+4],cl
  498                                                  mov [fdctab+2],ax       ; Segment 0
  499                                                  mov [fdctab],di         ; offset floppy_block
  500                                  %else
  501 00000050 8ED9                                    mov ds,cx               ; CX == 0
  502                                  %endif
  503                                  ;
  504                                  ; Ready to enable interrupts, captain
  505                                  ;
  506 00000052 FB                                      sti
  507                                  ;
  508                                  ; The drive number and possibly partition information was passed to us
  509                                  ; by the BIOS or previous boot loader (MBR).  Current "best practice" is to
  510                                  ; trust that rather than what the superblock contains.
  511                                  ;
  512                                  ; Would it be better to zero out bsHidden if we don't have a partition table?
  513                                  ;
  514                                  ; Note: di points to beyond the end of PartInfo
  515                                  ;
  516 00000053 8816[2400]                              mov [bsDriveNumber],dl
  517 00000057 F6C280                                  test dl,80h             ; If floppy disk (00-7F), assume no
  518 0000005A 7428                                    jz not_harddisk         ; partition table
  519 0000005C F645F07F                                test byte [di-16],7Fh   ; Sanity check: "active flag" should
  520 00000060 750A                                    jnz no_partition        ; be 00 or 80
  521 00000062 8D75F8                                  lea si,[di-8]           ; Partition offset (dword)
  522 00000065 BF[1C00]                                mov di,bsHidden1
  523 00000068 B102                                    mov cl,2                ; CH == 0
  524 0000006A F3A5                                    rep movsw
  525                                  no_partition:
  526                                  ;
  527                                  ; Get disk drive parameters (don't trust the superblock.)  Don't do this for
  528                                  ; floppy drives -- INT 13:08 on floppy drives will (may?) return info about
  529                                  ; what the *drive* supports, not about the *media*.  Fortunately floppy disks
  530                                  ; tend to have a fixed, well-defined geometry which is stored in the superblock.
  531                                  ;
  532                                                  ; DL == drive # still
  533 0000006C B408                                    mov ah,08h
  534 0000006E CD13                                    int 13h
  535 00000070 7212                                    jc no_driveparm
  536 00000072 20E4                                    and ah,ah
  537 00000074 750E                                    jnz no_driveparm
  538 00000076 FEC6                                    inc dh                  ; Contains # of heads - 1
  539 00000078 8836[1A00]                              mov [bsHeads],dh
  540 0000007C 81E13F00                                and cx,3fh
  541 00000080 890E[1800]                              mov [bsSecPerTrack],cx
  542                                  no_driveparm:
  543                                  not_harddisk:
  544                                  ;
  545                                  ; Now we have to do some arithmetric to figure out where things are located.
  546                                  ; If Micro$oft had had brains they would already have done this for us,
  547                                  ; and stored it in the superblock at format time, but here we go,
  548                                  ; wasting precious boot sector space again...
  549                                  ;
  550                                  debugentrypt:
  551 00000084 31C0                                    xor ax,ax               ; INT 13:08 destroys ES
  552 00000086 8EC0                                    mov es,ax
  553 00000088 A0[1000]                                mov al,[bsFATs]         ; Number of FATs (AH == 0)
  554 0000008B F726[1600]                              mul word [bsFATsecs]    ; Get the size of the FAT area
  555 0000008F 0306[1C00]                              add ax,[bsHidden1]      ; Add hidden sectors
  556 00000093 1316[1E00]                              adc dx,[bsHidden2]
  557 00000097 0306[0E00]                              add ax,[bsResSectors]   ; And reserved sectors
  558 0000009B 83D200                                  adc dx,byte 0
  559
  560 0000009E A3DC64                                  mov [RootDir1],ax       ; Location of root directory
  561 000000A1 8916DE64                                mov [RootDir2],dx
  562 000000A5 A3E064                                  mov [DataArea1],ax
  563 000000A8 8916E264                                mov [DataArea2],dx
  564 000000AC 50                                      push ax
  565 000000AD 52                                      push dx
  566
  567 000000AE B82000                                  mov ax,32               ; Size of a directory entry
  568 000000B1 F726[1100]                              mul word [bsRootDirEnts]
  569 000000B5 8B1E[0B00]                              mov bx,[bsBytesPerSec]
  570 000000B9 01D8                                    add ax,bx               ; Round up, not down
  571 000000BB 48                                      dec ax
  572 000000BC F7F3                                    div bx                  ; Now we have the size of the root dir
  573 000000BE A3E864                                  mov [RootDirSize],ax
  574 000000C1 A3EA64                                  mov [DirScanCtr],ax
  575 000000C4 81C3E10F                                add bx,trackbuf-31
  576 000000C8 891EEE64                                mov [EndofDirSec],bx    ; End of a single directory sector
  577
  578 000000CC 0106E064                                add [DataArea1],ax
  579 000000D0 8316E26400                              adc word [DataArea2],byte 0
  580
  581 000000D5 5A                                      pop dx                  ; Reload root directory starting point
  582 000000D6 58                                      pop ax
  583                                  ;
  584                                  ; Now the fun begins.  We have to search the root directory for
  585                                  ; LDLINUX.SYS and load the first sector, so we have a little more
  586                                  ; space to have fun with.  Then we can go chasing through the FAT.
  587                                  ; Joy!!
  588                                  ;
  589 000000D7 50                      sd_nextsec:     push ax
  590 000000D8 52                                      push dx
  591 000000D9 BB0010                                  mov bx,trackbuf
  592 000000DC 53                                      push bx
  593 000000DD E88F00                                  call getonesec
  594 000000E0 5E                                      pop si
  595 000000E1 803C00                  sd_nextentry:   cmp byte [si],0         ; Directory high water mark
  596 000000E4 7429                                    je kaboom
  597 000000E6 F6440B18                                test byte [si+11],18h   ; Must be a file
  598 000000EA 750C                                    jnz sd_not_file
  599 000000EC BF[EF01]                                mov di,ldlinux_name
  600 000000EF B90B00                                  mov cx,11
  601 000000F2 56                                      push si
  602 000000F3 F3A6                                    repe cmpsb
  603 000000F5 5E                                      pop si
  604 000000F6 742D                                    je found_it
  605 000000F8 83C620                  sd_not_file:    add si,byte 32          ; Distance to next
  606 000000FB 3B36EE64                                cmp si,[EndofDirSec]
  607 000000FF 72E0                                    jb sd_nextentry
  608 00000101 5A                                      pop dx
  609 00000102 58                                      pop ax
  610 00000103 83C001                                  add ax,byte 1
  611 00000106 83D200                                  adc dx,byte 0
  612 00000109 FF0EEA64                                dec word [DirScanCtr]
  613 0000010D 75C8                                    jnz sd_nextsec
  614                                  ;
  615                                  ; kaboom: write a message and bail out.
  616                                  ;
  617                                  kaboom:
  618 0000010F 31F6                                    xor si,si
  619 00000111 8ED6                                    mov ss,si
  620 00000113 BC0060                                  mov sp,StackBuf         ; Reset stack
  621 00000116 8EDE                                    mov ds,si               ; Reset data segment
  622 00000118 BE[DE01]                .patch:         mov si,bailmsg
  623 0000011B E83900                                  call writestr           ; Returns with AL = 0
  624 0000011E 98                                      cbw                     ; AH <- 0
  625 0000011F CD16                                    int 16h                 ; Wait for keypress
  626 00000121 CD19                                    int 19h                 ; And try once more to boot...
  627 00000123 EBFE                    .norge:         jmp short .norge        ; If int 19h returned; this is the end
  628
  629                                  ;
  630                                  ; found_it: now we compute the location of the first sector, then
  631                                  ;           load it and JUMP (since we're almost out of space)
  632                                  ;
  633                                  found_it:       ; Note: we actually leave two words on the stack here
  634                                                  ; (who cares?)
  635 00000125 31C0                                    xor ax,ax
  636 00000127 A0[0D00]                                mov al,[bsSecPerClust]
  637 0000012A 89C5                                    mov bp,ax               ; Load an entire cluster
  638 0000012C 8B5C1A                                  mov bx,[si+26]          ; First cluster
  639 0000012F 891EF064                                mov [RunLinClust],bx    ; Save for later use
  640 00000133 4B                                      dec bx                  ; First cluster is "cluster 2"
  641 00000134 4B                                      dec bx
  642 00000135 F7E3                                    mul bx
  643 00000137 0306E064                                add ax,[DataArea1]
  644 0000013B 1316E264                                adc dx,[DataArea2]
  645 0000013F BB[0002]                                mov bx,ldlinux_sys
  646 00000142 E82D00                                  call getlinsec
  647 00000145 BE[EF01]                                mov si,bs_magic
  648 00000148 BF[1F02]                                mov di,ldlinux_magic
  649 0000014B B91100                                  mov cx,magic_len
  650 0000014E F3A6                                    repe cmpsb              ; Make sure that the bootsector
  651 00000150 75BD                                    jne kaboom              ; matches LDLINUX.SYS
  652                                  ;
  653                                  ; Done! Jump to the entry point!
  654                                  ;
  655                                  ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000
  656                                  ; instead of 0000:7C00 and the like.  We don't want to add anything
  657                                  ; more to the boot sector, so it is written to not assume a fixed
  658                                  ; value in CS, but we don't want to deal with that anymore from now
  659                                  ; on.
  660                                  ;
  661 00000152 EA[3002]0000                            jmp 0:ldlinux_ent
  662
  663                                  ;
  664                                  ;
  665                                  ; writestr: write a null-terminated string to the console
  666                                  ;
  667                                  writestr:
  668 00000157 AC                      wstr_1:         lodsb
  669 00000158 20C0                                    and al,al
  670 0000015A 7412                                    jz return
  671 0000015C B40E                                    mov ah,0Eh              ; Write to screen as TTY
  672 0000015E BB0700                                  mov bx,0007h            ; White on black, current page
  673 00000161 CD10                                    int 10h
  674 00000163 EBF2                                    jmp short wstr_1
  675                                  ;
  676                                  ; disk_error: decrement the retry count and bail if zero
  677                                  ;
  678 00000165 4E                      disk_error:     dec si                  ; SI holds the disk retry counter
  679 00000166 74A7                                    jz kaboom
  680 00000168 93                                      xchg ax,bx              ; Shorter than MOV
  681 00000169 5B                                      pop bx                  ; <I>
  682 0000016A 59                                      pop cx                  ; <H>
  683 0000016B 5A                                      pop dx                  ; <G>
  684 0000016C EB3C                                    jmp short disk_try_again
  685
  686 0000016E C3                      return:         ret
  687
  688                                  ;
  689                                  ; getonesec: like getlinsec, but pre-sets the count to 1
  690                                  ;
  691                                  getonesec:
  692 0000016F BD0100                                  mov bp,1
  693                                                  ; Fall through to getlinsec
  694
  695                                  ;
  696                                  ; getlinsec: load a sequence of BP floppy sector given by the linear sector
  697                                  ;            number in DX:AX into the buffer at ES:BX.  We try to optimize
  698                                  ;            by loading up to a whole track at a time, but the user
  699                                  ;            is responsible for not crossing a 64K boundary.
  700                                  ;            (Yes, BP is weird for a count, but it was available...)
  701                                  ;
  702                                  ;            On return, BX points to the first byte after the transferred
  703                                  ;            block.
  704                                  ;
  705                                  ;            The "stupid patch area" gets replaced by the code
  706                                  ;            mov bp,1 ; nop ... (BD 01 00 90 90...) when installing with
  707                                  ;            the -s option.
  708                                  ;
  709                                  ; Stylistic note: use "xchg" instead of "mov" when the source is a register
  710                                  ; that is dead from that point; this saves space.  However, please keep
  711                                  ; the order to dst,src to keep things sane.
  712                                  ;
  713                                  getlinsec:
  714 00000172 8B36[1800]                              mov si,[bsSecPerTrack]
  715                                                  ;
  716                                                  ; Dividing by sectors to get (track,sector): we may have
  717                                                  ; up to 2^18 tracks, so we need to do this in two steps
  718                                                  ; to produce a 32-bit quotient.
  719                                                  ;
  720 00000176 91                                      xchg cx,ax              ; CX <- LSW of LBA
  721 00000177 92                                      xchg ax,dx
  722 00000178 31D2                                    xor dx,dx               ; DX:AX now == MSW of LBA
  723 0000017A F7F6                                    div si                  ; Obtain MSW of track #
  724 0000017C 91                                      xchg ax,cx              ; Remainder -> MSW of new dividend
  725                                                                          ; LSW of LBA -> LSW of new dividend
  726                                                                          ; Quotient -> MSW of track #
  727 0000017D F7F6                                    div si                  ; Obtain LSW of track #, remainder
  728 0000017F 87CA                                    xchg cx,dx              ; CX <- Sector index (0-based)
  729                                                                          ; DX <- MSW of track #
  730 00000181 F736[1A00]                              div word [bsHeads]      ; Convert track to head/cyl
  731                                                  ;
  732                                                  ; Now we have AX = cyl, DX = head, CX = sector (0-based),
  733                                                  ; BP = sectors to transfer, SI = bsSecPerTrack,
  734                                                  ; ES:BX = data target
  735                                                  ;
  736 00000185 56                      gls_nextchunk:  push si                 ; <A> bsSecPerTrack
  737 00000186 55                                      push bp                 ; <B> Sectors to transfer
  738
  739                                  __BEGIN_STUPID_PATCH_AREA:
  740 00000187 29CE                                    sub si,cx               ; Sectors left on track
  741 00000189 39F5                                    cmp bp,si
  742 0000018B 7602                                    jna gls_lastchunk
  743 0000018D 89F5                                    mov bp,si               ; No more than a trackful, please!
  744                                  __END_STUPID_PATCH_AREA:
  745                                  gls_lastchunk:
  746 0000018F 50                                      push ax                 ; <C> Cylinder #
  747 00000190 52                                      push dx                 ; <D> Head #
  748
  749 00000191 51                                      push cx                 ; <E> Sector #
  750 00000192 B106                                    mov cl,6                ; Because IBM was STOOPID
  751 00000194 D2E4                                    shl ah,cl               ; and thought 8 bits were enough
  752                                                                          ; then thought 10 bits were enough...
  753 00000196 59                                      pop cx                  ; <E> Sector #
  754 00000197 51                                      push cx                 ; <E> Sector #
  755 00000198 41                                      inc cx                  ; Sector numbers are 1-based
  756 00000199 08E1                                    or cl,ah
  757 0000019B 88C5                                    mov ch,al
  758 0000019D 88D6                                    mov dh,dl
  759 0000019F 8A16[2400]                              mov dl,[bsDriveNumber]
  760 000001A3 95                                      xchg ax,bp              ; Sector to transfer count
  761                                                                          ; (xchg shorter than mov)
  762 000001A4 50                                      push ax                 ; <F> Number of sectors we're transferring
  763 000001A5 B402                                    mov ah,02h              ; Read it!
  764                                  ;
  765                                  ; Do the disk transfer... save the registers in case we fail :(
  766                                  ;
  767 000001A7 BE0600                                  mov si,retry_count      ; # of times to retry a disk access
  768 000001AA 52                      disk_try_again: push dx                 ; <G>
  769 000001AB 51                                      push cx                 ; <H>
  770 000001AC 53                                      push bx                 ; <I>
  771 000001AD 50                                      push ax                 ; <J>
  772 000001AE 56                                      push si                 ; <K>
  773 000001AF CD13                                    int 13h
  774 000001B1 5E                                      pop si                  ; <K>
  775 000001B2 5B                                      pop bx                  ; <J>
  776 000001B3 72B0                                    jc disk_error
  777                                  ;
  778                                  ; Disk access successful
  779                                  ;
  780 000001B5 5B                                      pop bx                  ; <I> Buffer location
  781 000001B6 58                                      pop ax                  ; <H> No longer needed
  782 000001B7 58                                      pop ax                  ; <G> No longer needed
  783 000001B8 5F                                      pop di                  ; <F> Sector transferred count
  784 000001B9 59                                      pop cx                  ; <E> Sector #
  785 000001BA 89F8                                    mov ax,di               ; Reduce sector left count
  786 000001BC F726[0B00]                              mul word [bsBytesPerSec] ; Figure out how much to advance ptr
  787 000001C0 01C3                                    add bx,ax               ; Update buffer location
  788 000001C2 5A                                      pop dx                  ; <D> Head #
  789 000001C3 58                                      pop ax                  ; <C> Cyl #
  790 000001C4 5D                                      pop bp                  ; <B> Sectors left to transfer
  791 000001C5 5E                                      pop si                  ; <A> Number of sectors/track
  792 000001C6 29FD                                    sub bp,di               ; Reduce with # of sectors just read
  793 000001C8 74A4                                    jz return               ; Done!
  794 000001CA 01F9                                    add cx,di
  795 000001CC 39F1                                    cmp cx,si
  796 000001CE 72B5                                    jb gls_nextchunk
  797 000001D0 42                                      inc dx                  ; Next track on cyl
  798 000001D1 3B16[1A00]                              cmp dx,[bsHeads]        ; Was this the last one?
  799 000001D5 7203                                    jb gls_nonewcyl
  800 000001D7 40                                      inc ax                  ; If so, new cylinder
  801 000001D8 31D2                                    xor dx,dx               ; First head on new cylinder
  802 000001DA 29F1                    gls_nonewcyl:   sub cx,si               ; First sector on new track
  803 000001DC EBA7                                    jmp short gls_nextchunk
  804
  805 000001DE 426F6F74206661696C-     bailmsg:        db 'Boot failed', 0Dh, 0Ah, 0
  806 000001E7 65640D0A00
  807
  808                                  bs_checkpt      equ $                   ; Must be <= 1EFh
  809
  810                                                  zb 1EFh-($-$$)
  811 000001EC 00<rept>            <1>         times %1 db 0
  812                                  bs_magic        equ $                   ; From here to the magic_len equ
  813                                                                          ; must match ldlinux_magic
  814 000001EF 4C444C494E55582053-     ldlinux_name:   db 'LDLINUX SYS'        ; Looks like this in the root dir
  815 000001F8 5953
  816 000001FA 34C66537                                dd HEXDATE              ; Hopefully unique between compiles
  817
  818 000001FE 55AA                    bootsignature   dw 0AA55h
  819                                  magic_len       equ $-bs_magic
  820
  821                                  ;
  822                                  ; ===========================================================================
  823                                  ;  End of boot sector
  824                                  ; ===========================================================================
  825                                  ;  Start of LDLINUX.SYS
  826                                  ; ===========================================================================
  827
  828                                  ldlinux_sys:
  829
  830 00000200 0D0A5359534C494E55-     syslinux_banner db 0Dh, 0Ah, 'SYSLINUX ', version_str, ' ', date, ' ', 0
  831 00000209 5820312E3435203139-
  832 00000212 39392D30362D313420-
  833 0000021B 00
  834 0000021C 0D0A1A                                  db 0Dh, 0Ah, 1Ah        ; EOF if we "type" this in DOS
  835
  836 0000021F 4C444C494E55582053-     ldlinux_magic   db 'LDLINUX SYS'
  837 00000228 5953
  838 0000022A 34C66537                                dd HEXDATE
  839 0000022E 55AA                                    dw 0AA55h
  840
  841                                                  align 4
  842
  843                                  ldlinux_ent:
  844                                  ;
  845                                  ; Tell the user we got this far
  846                                  ;
  847 00000230 BE[0002]                                mov si,syslinux_banner
  848 00000233 E821FF                                  call writestr
  849                                  ;
  850                                  ; Remember, the boot sector loaded only the first cluster of LDLINUX.SYS.
  851                                  ; We can really only rely on a single sector having been loaded.  Hence
  852                                  ; we should load the FAT into RAM and start chasing pointers...
  853                                  ;
  854 00000236 BA0100                                  mov dx,1                        ; 64K
  855 00000239 31C0                                    xor ax,ax
  856 0000023B F736[0B00]                              div word [bsBytesPerSec]        ; sectors/64K
  857 0000023F 89C6                                    mov si,ax
  858
  859 00000241 06                                      push es
  860 00000242 BB0050                                  mov bx,fat_seg                  ; Load into fat_seg:0000
  861 00000245 8EC3                                    mov es,bx
  862
  863 00000247 A1[1C00]                                mov ax,[bsHidden1]              ; Hidden sectors
  864 0000024A 8B16[1E00]                              mov dx,[bsHidden2]
  865 0000024E 0306[0E00]                              add ax,[bsResSectors]           ; plus reserved sectors = FAT
  866 00000252 83D200                                  adc dx,byte 0
  867 00000255 8B0E[1600]                              mov cx,[bsFATsecs]              ; Sectors/FAT
  868                                  fat_load_loop:
  869 00000259 89CD                                    mov bp,cx
  870 0000025B 39F5                                    cmp bp,si
  871 0000025D 7602                                    jna fat_load
  872 0000025F 89F5                                    mov bp,si                       ; A full 64K moby
  873                                  fat_load:
  874 00000261 31DB                                    xor bx,bx                       ; Offset 0 in the current ES
  875 00000263 E82201                                  call getlinsecsr
  876 00000266 29E9                                    sub cx,bp
  877 00000268 740F                                    jz fat_load_done                ; Last moby?
  878 0000026A 01E8                                    add ax,bp                       ; Advance sector count
  879 0000026C 83D200                                  adc dx,byte 0
  880 0000026F 8CC3                                    mov bx,es                       ; Next 64K moby
  881 00000271 81C30010                                add bx,1000h
  882 00000275 8EC3                                    mov es,bx
  883 00000277 EBE0                                    jmp short fat_load_loop
  884                                  fat_load_done:
  885 00000279 07                                      pop es
  886                                  ;
  887                                  ; Fine, now we have the FAT in memory.  How big is a cluster, really?
  888                                  ; Also figure out how many clusters will fit in an 8K buffer, and how
  889                                  ; many sectors and bytes that is
  890                                  ;
  891 0000027A 8B3E[0B00]                              mov di,[bsBytesPerSec]          ; Used a lot below
  892
  893 0000027E A0[0D00]                                mov al,[bsSecPerClust]          ; We do this in the boot
  894 00000281 30E4                                    xor ah,ah                       ; sector, too, but there
  895 00000283 A3F464                                  mov [SecPerClust],ax            ; wasn't space to save it
  896 00000286 89C6                                    mov si,ax                       ; Also used a lot...
  897 00000288 F7E7                                    mul di
  898 0000028A A3F264                                  mov [ClustSize],ax              ; Bytes/cluster
  899 0000028D 89C3                                    mov bx,ax
  900 0000028F B80040                                  mov ax,trackbufsize
  901 00000292 31D2                                    xor dx,dx
  902 00000294 F7F3                                    div bx
  903 00000296 A3F864                                  mov [BufSafe],ax                ; # of cluster in trackbuf
  904 00000299 F726F464                                mul word [SecPerClust]
  905 0000029D A3FA64                                  mov [BufSafeSec],ax
  906 000002A0 F7E7                                    mul di
  907 000002A2 A3FC64                                  mov [BufSafeBytes],ax
  908 000002A5 050098                                  add ax,getcbuf                  ; Size of getcbuf is the same
  909 000002A8 A3FE64                                  mov [EndOfGetCBuf],ax           ; as for trackbuf
  910                                  ;
  911                                  ; FAT12 or FAT16?  This computation is fscking ridiculous...
  912                                  ;
  913 000002AB 31D2                                    xor dx,dx
  914 000002AD 31C9                                    xor cx,cx
  915 000002AF A1[1300]                                mov ax,[bsSectors]
  916 000002B2 21C0                                    and ax,ax
  917 000002B4 7507                                    jnz have_secs
  918 000002B6 A1[2000]                                mov ax,[bsHugeSectors]
  919 000002B9 8B16[2200]                              mov dx,[bsHugeSectors+2]
  920 000002BD 2B06[0E00]              have_secs:      sub ax,[bsResSectors]
  921 000002C1 83DA00                                  sbb dx,byte 0
  922 000002C4 8A0E[1000]                              mov cl,[bsFATs]
  923 000002C8 2B06[1600]              sec_fat_loop:   sub ax,[bsFATsecs]
  924 000002CC 83DA00                                  sbb dx,byte 0
  925 000002CF E2F7                                    loop sec_fat_loop
  926 000002D1 50                                      push ax
  927 000002D2 52                                      push dx
  928 000002D3 A1[1100]                                mov ax,[bsRootDirEnts]
  929 000002D6 BB2000                                  mov bx,32                       ; Smaller than shift since we
  930 000002D9 F7E3                                    mul bx                          ; need the doubleword product
  931 000002DB 01F8                                    add ax,di
  932 000002DD 83D200                                  adc dx,byte 0
  933 000002E0 83E801                                  sub ax,byte 1
  934 000002E3 83DA00                                  sbb dx,byte 0
  935 000002E6 F7F7                                    div di
  936 000002E8 89C3                                    mov bx,ax
  937 000002EA 5A                                      pop dx
  938 000002EB 58                                      pop ax
  939 000002EC 29D8                                    sub ax,bx
  940 000002EE 83DA00                                  sbb dx,byte 0
  941 000002F1 F7F6                                    div si
  942 000002F3 3DF60F                                  cmp ax,4086                     ; Right value?
  943 000002F6 B8[BF03]                                mov ax,nextcluster_fat16
  944 000002F9 7703                                    ja have_fat_type
  945 000002FB B8[9803]                have_fat12:     mov ax,nextcluster_fat12
  946 000002FE A3F664                  have_fat_type:  mov word [NextCluster],ax
  947
  948                                  ;
  949                                  ; Now we read the rest of LDLINUX.SYS.  Don't bother loading the first
  950                                  ; cluster again, though.
  951                                  ;
  952                                  load_rest:
  953 00000301 8B0EF264                                mov cx,[ClustSize]
  954 00000305 BB[0002]                                mov bx,ldlinux_sys
  955 00000308 01CB                                    add bx,cx
  956 0000030A 8B36F064                                mov si,[RunLinClust]
  957 0000030E FF16F664                                call [NextCluster]
  958 00000312 31D2                                    xor dx,dx
  959 00000314 B8C518                                  mov ax,ldlinux_len-1            ; To be on the safe side
  960 00000317 01C8                                    add ax,cx
  961 00000319 F7F1                                    div cx                          ; the number of clusters
  962 0000031B 48                                      dec ax                          ; We've already read one
  963 0000031C 7405                                    jz all_read_jmp
  964 0000031E 89C1                                    mov cx,ax
  965 00000320 E80300                                  call getfssec
  966                                  ;
  967                                  ; All loaded up
  968                                  ;
  969                                  all_read_jmp:
  970 00000323 E9B100                                  jmp all_read
  971                                  ;
  972                                  ; -----------------------------------------------------------------------------
  973                                  ; Subroutines that have to be in the first sector
  974                                  ; -----------------------------------------------------------------------------
  975                                  ;
  976                                  ; getfssec: Get multiple clusters from a file, given the starting cluster.
  977                                  ;
  978                                  ;       This routine makes sure the subtransfers do not cross a 64K boundary,
  979                                  ;       and will correct the situation if it does, UNLESS *sectors* cross
  980                                  ;       64K boundaries.
  981                                  ;
  982                                  ;       ES:BX   -> Buffer
  983                                  ;       SI      -> Starting cluster number (2-based)
  984                                  ;       CX      -> Cluster count (0FFFFh = until end of file)
  985                                  ;
  986                                                                                  ; 386 check
  987                                  getfssec:
  988 00000326 31ED                    getfragment:    xor bp,bp                       ; Fragment sector count
  989 00000328 89F0                                    mov ax,si                       ; Get sector address
  990 0000032A 48                                      dec ax                          ; Convert to 0-based
  991 0000032B 48                                      dec ax
  992 0000032C F726F464                                mul word [SecPerClust]
  993 00000330 0306E064                                add ax,[DataArea1]
  994 00000334 1316E264                                adc dx,[DataArea2]
  995                                  getseccnt:                                      ; See if we can read > 1 clust
  996 00000338 032EF464                                add bp,[SecPerClust]
  997 0000033C 49                                      dec cx                          ; Reduce clusters left to find
  998 0000033D 89F7                                    mov di,si                       ; Predict next cluster
  999 0000033F 47                                      inc di
 1000 00000340 FF16F664                                call [NextCluster]
 1001 00000344 7207                                    jc gfs_eof                      ; At EOF?
 1002 00000346 E304                                    jcxz endfragment                ; Or was it the last we wanted?
 1003 00000348 39FE                                    cmp si,di                       ; Is file continuous?
 1004 0000034A 74EC                                    jz getseccnt                    ; Yes, we can get
 1005 0000034C F8                      endfragment:    clc                             ; Not at EOF
 1006 0000034D 9C                      gfs_eof:        pushf                           ; Remember EOF or not
 1007 0000034E 56                                      push si
 1008 0000034F 51                                      push cx
 1009                                  gfs_getchunk:
 1010 00000350 50                                      push ax
 1011 00000351 52                                      push dx
 1012 00000352 8CC0                                    mov ax,es                       ; Check for 64K boundaries.
 1013 00000354 B104                                    mov cl,4
 1014 00000356 D3E0                                    shl ax,cl
 1015 00000358 01D8                                    add ax,bx
 1016 0000035A 31D2                                    xor dx,dx
 1017 0000035C F7D8                                    neg ax
 1018 0000035E 7501                                    jnz gfs_partseg
 1019 00000360 42                                      inc dx                          ; Full 64K segment
 1020                                  gfs_partseg:
 1021 00000361 F736[0B00]                              div word [bsBytesPerSec]        ; How many sectors fit?
 1022 00000365 89EE                                    mov si,bp
 1023 00000367 29C6                                    sub si,ax                       ; Compute remaining sectors
 1024 00000369 7610                                    jbe gfs_lastchunk
 1025 0000036B 89C5                                    mov bp,ax
 1026 0000036D 5A                                      pop dx
 1027 0000036E 58                                      pop ax
 1028 0000036F E81600                                  call getlinsecsr
 1029 00000372 01E8                                    add ax,bp
 1030 00000374 83D200                                  adc dx,byte 0
 1031 00000377 89F5                                    mov bp,si                       ; Remaining sector count
 1032 00000379 EBD5                                    jmp short gfs_getchunk
 1033 0000037B 5A                      gfs_lastchunk:  pop dx
 1034 0000037C 58                                      pop ax
 1035 0000037D E8F2FD                                  call getlinsec
 1036 00000380 59                                      pop cx
 1037 00000381 5E                                      pop si
 1038 00000382 9D                                      popf
 1039 00000383 E302                                    jcxz gfs_return                 ; If we hit the count limit
 1040 00000385 739F                                    jnc getfragment                 ; If we didn't hit EOF
 1041 00000387 C3                      gfs_return:     ret
 1042
 1043                                  ;
 1044                                  ; getlinsecsr: save registers, call getlinsec, restore registers
 1045                                  ;
 1046 00000388 50                      getlinsecsr:    push ax
 1047 00000389 52                                      push dx
 1048 0000038A 51                                      push cx
 1049 0000038B 55                                      push bp
 1050 0000038C 56                                      push si
 1051 0000038D 57                                      push di
 1052 0000038E E8E1FD                                  call getlinsec
 1053 00000391 5F                                      pop di
 1054 00000392 5E                                      pop si
 1055 00000393 5D                                      pop bp
 1056 00000394 59                                      pop cx
 1057 00000395 5A                                      pop dx
 1058 00000396 58                                      pop ax
 1059 00000397 C3                                      ret
 1060
 1061                                  ;
 1062                                  ; nextcluster: Advance a cluster pointer in SI to the next cluster
 1063                                  ;              pointed at in the FAT tables (note: FAT12 assumed)
 1064                                  ;              Sets CF on return if end of file.
 1065                                  ;
 1066                                  ;              The variable NextCluster gets set to the appropriate
 1067                                  ;              value here.
 1068                                  ;
 1069                                  nextcluster_fat12:
 1070 00000398 50                                      push ax
 1071 00000399 1E                                      push ds
 1072 0000039A B80050                                  mov ax,fat_seg
 1073 0000039D 8ED8                                    mov ds,ax
 1074 0000039F 89F0                                    mov ax,si                       ; Multiply by 3/2
 1075 000003A1 D1E8                                    shr ax,1
 1076 000003A3 9C                                      pushf                           ; CF now set if odd
 1077 000003A4 01C6                                    add si,ax
 1078 000003A6 8B34                                    mov si,[si]
 1079 000003A8 9D                                      popf
 1080 000003A9 7308                                    jnc nc_even
 1081 000003AB D1EE                                    shr si,1                        ; Needed for odd only
 1082 000003AD D1EE                                    shr si,1
 1083 000003AF D1EE                                    shr si,1
 1084 000003B1 D1EE                                    shr si,1
 1085                                  nc_even:
 1086 000003B3 81E6FF0F                                and si,0FFFh
 1087 000003B7 81FEF00F                                cmp si,0FF0h                    ; Clears CF if at end of file
 1088 000003BB F5                                      cmc                             ; But we want it SET...
 1089 000003BC 1F                                      pop ds
 1090 000003BD 58                                      pop ax
 1091 000003BE C3                      nc_return:      ret
 1092
 1093                                  ;
 1094                                  ; FAT16 decoding routine.  Note that a 16-bit FAT can be up to 128K,
 1095                                  ; so we have to decide if we're in the "low" or the "high" 64K-segment...
 1096                                  ;
 1097                                  nextcluster_fat16:
 1098 000003BF 50                                      push ax
 1099 000003C0 1E                                      push ds
 1100 000003C1 B80050                                  mov ax,fat_seg
 1101 000003C4 D1E6                                    shl si,1
 1102 000003C6 7303                                    jnc .seg0
 1103 000003C8 B80060                                  mov ax,fat_seg+1000h
 1104 000003CB 8ED8                    .seg0:          mov ds,ax
 1105 000003CD 8B34                                    mov si,[si]
 1106 000003CF 81FEF0FF                                cmp si,0FFF0h
 1107 000003D3 F5                                      cmc
 1108 000003D4 1F                                      pop ds
 1109 000003D5 58                                      pop ax
 1110 000003D6 C3                                      ret
 1111                                  ;
 1112                                  ; Debug routine
 1113                                  ;
 1114                                  %ifdef debug
 1115                                  safedumpregs:
 1116                                                  cmp word [Debug_Magic],0D00Dh
 1117                                                  jnz nc_return
 1118                                                  jmp dumpregs
 1119                                  %endif
 1120
 1121                                  rl_checkpt      equ $                           ; Must be <= 400h
 1122
 1123                                  ; ----------------------------------------------------------------------------
 1124                                  ;  End of code and data that have to be in the first sector
 1125                                  ; ----------------------------------------------------------------------------
 1126
 1127                                  all_read:
 1128                                  ;
 1129                                  ; Let the user (and programmer!) know we got this far.  This used to be
 1130                                  ; in Sector 1, but makes a lot more sense here.
 1131                                  ;
 1132 000003D7 BE[6914]                                mov si,copyright_str
 1133 000003DA E87AFD                                  call writestr
 1134                                  ;
 1135                                  ; Check that no moron is trying to boot Linux on a 286 or so.  According
 1136                                  ; to Intel, the way to check is to see if the high 4 bits of the FLAGS
 1137                                  ; register are either all stuck at 1 (8086/8088) or all stuck at 0
 1138                                  ; (286 in real mode), if not it is a 386 or higher.  They didn't
 1139                                  ; say how to check for a 186/188, so I *hope* it falls out as a 8086
 1140                                  ; or 286 in this test.
 1141                                  ;
 1142                                  ; Also, provide an escape route in case it doesn't work.
 1143                                  ;
 1144                                  check_escapes:
 1145 000003DD B402                                    mov ah,02h                      ; Check keyboard flags
 1146 000003DF CD16                                    int 16h
 1147 000003E1 A22165                                  mov [KbdFlags],al               ; Save for boot prompt check
 1148 000003E4 A804                                    test al,04h                     ; Ctrl->skip 386 check
 1149 000003E6 7538                                    jnz skip_checks
 1150                                  test_8086:
 1151 000003E8 9C                                      pushf                           ; Get flags
 1152 000003E9 58                                      pop ax
 1153 000003EA 25FF0F                                  and ax,0FFFh                    ; Clear top 4 bits
 1154 000003ED 50                                      push ax                         ; Load into FLAGS
 1155 000003EE 9D                                      popf
 1156 000003EF 9C                                      pushf                           ; And load back
 1157 000003F0 58                                      pop ax
 1158 000003F1 2500F0                                  and ax,0F000h                   ; Get top 4 bits
 1159 000003F4 3D00F0                                  cmp ax,0F000h                   ; If set -> 8086/8088
 1160 000003F7 740E                                    je not_386
 1161                                  test_286:
 1162 000003F9 9C                                      pushf                           ; Get flags
 1163 000003FA 58                                      pop ax
 1164 000003FB 0D00F0                                  or ax,0F000h                    ; Set top 4 bits
 1165 000003FE 50                                      push ax
 1166 000003FF 9D                                      popf
 1167 00000400 9C                                      pushf
 1168 00000401 58                                      pop ax
 1169 00000402 2500F0                                  and ax,0F000h                   ; Get top 4 bits
 1170 00000405 7509                                    jnz is_386                      ; If not clear -> 386
 1171                                  not_386:
 1172 00000407 BE[E114]                                mov si,err_not386
 1173 0000040A E84AFD                                  call writestr
 1174 0000040D E9FFFC                                  jmp kaboom
 1175                                  is_386:
 1176                                                  ; Now we know it's a 386 or higher
 1177                                  ;
 1178                                  ; Now check that there is at least 608K of low (DOS) memory
 1179                                  ; (608K = 9800h segments)
 1180                                  ;
 1181 00000410 CD12                                    int 12h
 1182 00000412 3D6002                                  cmp ax,608
 1183 00000415 7309                                    jae enough_ram
 1184 00000417 BE[CE15]                                mov si,err_noram
 1185 0000041A E83AFD                                  call writestr
 1186 0000041D E9EFFC                                  jmp kaboom
 1187                                  enough_ram:
 1188                                  skip_checks:
 1189                                  ;
 1190                                  ; Check if we're 386 (as opposed to 486+); if so we need to blank out
 1191                                  ; the WBINVD instruction
 1192                                  ;
 1193                                  ; We check for 486 by setting EFLAGS.AC
 1194                                  ;
 1195 00000420 669C                                    pushfd                          ; Save the good flags
 1196 00000422 669C                                    pushfd
 1197 00000424 6658                                    pop eax
 1198 00000426 6689C3                                  mov ebx,eax
 1199 00000429 663500000400                            xor eax,(1 << 18)               ; AC bit
 1200 0000042F 6650                                    push eax
 1201 00000431 669D                                    popfd
 1202 00000433 669C                                    pushfd
 1203 00000435 6658                                    pop eax
 1204 00000437 669D                                    popfd                           ; Restore the original flags
 1205 00000439 6631D8                                  xor eax,ebx
 1206 0000043C 7505                                    jnz is_486
 1207                                  ;
 1208                                  ; 386 - Looks like we better blot out the WBINVD instruction
 1209                                  ;
 1210 0000043E C606[700E]C3                            mov byte [try_wbinvd],0c3h              ; Near RET
 1211                                  is_486:
 1212
 1213                                  ;
 1214                                  ; Initialization that does not need to go into the any of the pre-load
 1215                                  ; areas
 1216                                  ;
 1217 00000443 E8580B                                  call adjust_screen
 1218                                  ;
 1219                                  ; Now, everything is "up and running"... patch kaboom for more
 1220                                  ; verbosity and using the full screen system
 1221                                  ;
 1222 00000446 C606[1801]E9                            mov byte [kaboom.patch],0e9h            ; JMP NEAR
 1223 0000044B C706[1901]8A10                          mov word [kaboom.patch+1],kaboom2-(kaboom.patch+3)
 1224
 1225                                  ;
 1226                                  ; Now we're all set to start with our *real* business.  First load the
 1227                                  ; configuration file (if any) and parse it.
 1228                                  ;
 1229                                  ; In previous versions I avoided using 32-bit registers because of a
 1230                                  ; rumour some BIOSes clobbered the upper half of 32-bit registers at
 1231                                  ; random.  I figure, though, that if there are any of those still left
 1232                                  ; they probably won't be trying to install Linux on them...
 1233                                  ;
 1234                                  ; The code is still ripe with 16-bitisms, though.  Not worth the hassle
 1235                                  ; to take'm out.  In fact, we may want to put them back if we're going
 1236                                  ; to boot ELKS at some point.
 1237                                  ;
 1238 00000451 BE[CE18]                                mov si,linuxauto_cmd            ; Default command: "linux auto"
 1239 00000454 BF[E519]                                mov di,default_cmd
 1240 00000457 B90B00                                  mov cx,linuxauto_len
 1241 0000045A F3A4                                    rep movsb
 1242
 1243 0000045C BF0063                                  mov di,KbdMap                   ; Default keymap 1:1
 1244 0000045F 30C0                                    xor al,al
 1245 00000461 B90001                                  mov cx,256
 1246 00000464 AA                      mkkeymap:       stosb
 1247 00000465 FEC0                                    inc al
 1248 00000467 E2FB                                    loop mkkeymap
 1249
 1250                                  ;
 1251                                  ; Load configuration file
 1252                                  ;
 1253 00000469 BF[6A18]                                mov di,syslinux_cfg
 1254 0000046C E8430D                                  call open
 1255 0000046F 0F840D02                                jz near no_config_file
 1256                                  parse_config:
 1257 00000473 E8D80D                                  call getkeyword
 1258 00000476 0F820302                                jc near end_config_file         ; Config file loaded
 1259 0000047A 3D6465                                  cmp ax,'de'                     ; DEfault
 1260 0000047D 7449                                    je pc_default
 1261 0000047F 3D6170                                  cmp ax,'ap'                     ; APpend
 1262 00000482 7454                                    je pc_append
 1263 00000484 3D7469                                  cmp ax,'ti'                     ; TImeout
 1264 00000487 0F849C00                                je near pc_timeout
 1265 0000048B 3D7072                                  cmp ax,'pr'                     ; PRompt
 1266 0000048E 0F84B200                                je near pc_prompt
 1267 00000492 3D666F                                  cmp ax,'fo'                     ; FOnt
 1268 00000495 0F848E01                                je near pc_font
 1269 00000499 3D6B62                                  cmp ax,'kb'                     ; KBd
 1270 0000049C 0F849101                                je near pc_kbd
 1271 000004A0 3D6469                                  cmp ax,'di'                     ; DIsplay
 1272 000004A3 0F849200                                je near pc_display
 1273 000004A7 3D6C61                                  cmp ax,'la'                     ; LAbel
 1274 000004AA 0F844601                                je near pc_label
 1275 000004AE 3D6B65                                  cmp ax,'ke'                     ; KErnel
 1276 000004B1 745B                                    je pc_kernel
 1277 000004B3 3D696D                                  cmp ax,'im'                     ; IMplicit
 1278 000004B6 0F849500                                je near pc_implicit
 1279 000004BA 3D7365                                  cmp ax,'se'                     ; SErial
 1280 000004BD 0F849900                                je near pc_serial
 1281 000004C1 3C66                                    cmp al,'f'                      ; F-key
 1282 000004C3 75AE                                    jne parse_config
 1283 000004C5 E90201                                  jmp pc_fkey
 1284
 1285 000004C8 BF[E519]                pc_default:     mov di,default_cmd              ; "default" command
 1286 000004CB E8910E                                  call getline
 1287 000004CE BE[D418]                                mov si,auto_cmd                 ; add "auto"+null
 1288 000004D1 B90500                                  mov cx,auto_len
 1289 000004D4 F3A4                                    rep movsb
 1290 000004D6 EB9B                                    jmp short parse_config
 1291
 1292 000004D8 833E[C618]00            pc_append:      cmp word [VKernelCtr],byte 0    ; "append" command
 1293 000004DD 7710                                    ja pc_append_vk
 1294 000004DF BF0062                                  mov di,AppendBuf
 1295 000004E2 E87A0E                                  call getline
 1296 000004E5 81EF0062                                sub di,AppendBuf
 1297 000004E9 893E[BC18]              pc_app1:        mov [AppendLen],di
 1298 000004ED EB84                                    jmp short parse_config
 1299 000004EF BF1860                  pc_append_vk:   mov di,VKernelBuf+vk_append     ; "append" command (vkernel)
 1300 000004F2 E86A0E                                  call getline
 1301 000004F5 81EF1860                                sub di,VKernelBuf+vk_append
 1302 000004F9 83FF02                                  cmp di,byte 2
 1303 000004FC 750A                                    jne pc_app2
 1304 000004FE 803E18602D                              cmp byte [VKernelBuf+vk_append],'-'
 1305 00000503 7503                                    jne pc_app2
 1306 00000505 BF0000                                  mov di,0                        ; If "append -" -> null string
 1307 00000508 893E1660                pc_app2:        mov [VKernelBuf+vk_appendlen],di
 1308 0000050C EB33                                    jmp short parse_config_2
 1309
 1310 0000050E 833E[C618]00            pc_kernel:      cmp word [VKernelCtr],byte 0    ; "kernel" command
 1311 00000513 0F845CFF                                je near parse_config            ; ("label" section only)
 1312 00000517 BF0010                                  mov di,trackbuf
 1313 0000051A 57                                      push di
 1314 0000051B E8410E                                  call getline
 1315 0000051E 5E                                      pop si
 1316 0000051F BF0B60                                  mov di,VKernelBuf+vk_rname
 1317 00000522 E8770E                                  call mangle_name
 1318 00000525 EB1A                                    jmp short parse_config_2
 1319
 1320 00000527 E8800D                  pc_timeout:     call getint                     ; "timeout" command
 1321 0000052A 7215                                    jc parse_config_2
 1322 0000052C B815D2                                  mov ax,0D215h                   ; There are approx 1.D215h
 1323 0000052F F7E3                                    mul bx                          ; clock ticks per 1/10 s
 1324 00000531 01D3                                    add bx,dx
 1325 00000533 891E[BE18]                              mov [KbdTimeOut],bx
 1326 00000537 EB08                                    jmp short parse_config_2
 1327
 1328 00000539 E80001                  pc_display:     call pc_getfile                 ; "display" command
 1329 0000053C 7403                                    jz parse_config_2               ; File not found?
 1330 0000053E E8D60A                                  call get_msg_file               ; Load and display file
 1331 00000541 E92FFF                  parse_config_2: jmp parse_config
 1332
 1333 00000544 E8630D                  pc_prompt:      call getint                     ; "prompt" command
 1334 00000547 72F8                                    jc parse_config_2
 1335 00000549 891E[C818]                              mov [ForcePrompt],bx
 1336 0000054D EBF2                                    jmp short parse_config_2
 1337
 1338 0000054F E8580D                  pc_implicit:    call getint                     ; "implicit" command
 1339 00000552 72ED                                    jc parse_config_2
 1340 00000554 891E[CA18]                              mov [AllowImplicit],bx
 1341 00000558 EBE7                                    jmp short parse_config_2
 1342
 1343 0000055A E84D0D                  pc_serial:      call getint                     ; "serial" command
 1344 0000055D 72E2                                    jc parse_config_2
 1345 0000055F 53                                      push bx                         ; Serial port #
 1346 00000560 E8D20C                                  call skipspace
 1347 00000563 72DC                                    jc parse_config_2
 1348 00000565 E8BC0C                                  call ungetc
 1349 00000568 E83F0D                                  call getint
 1350 0000056B 7306                                    jnc .valid_baud
 1351 0000056D 66BB80250000                            mov ebx,DEFAULT_BAUD            ; No baud rate given
 1352 00000573 5F                      .valid_baud:    pop di                          ; Serial port #
 1353 00000574 6683FB4B                                cmp ebx,byte 75
 1354 00000578 72C7                                    jb parse_config_2               ; < 75 baud == bogus
 1355 0000057A 66B800C20100                            mov eax,BAUD_DIVISOR
 1356 00000580 6699                                    cdq
 1357 00000582 66F7F3                                  div ebx
 1358 00000585 50                                      push ax                         ; Baud rate divisor
 1359 00000586 89FA                                    mov dx,di
 1360 00000588 D1E7                                    shl di,1
 1361 0000058A 8B850004                                mov ax,[di+serial_base]
 1362 0000058E A3[CC18]                                mov [SerialPort],ax
 1363 00000591 50                                      push ax                         ; Serial port base
 1364 00000592 B8E300                                  mov ax,00e3h                    ; INT 14h init parameters
 1365 00000595 CD14                                    int 14h                         ; Init serial port
 1366 00000597 5B                                      pop bx                          ; Serial port base
 1367 00000598 8D5703                                  lea dx,[bx+3]
 1368 0000059B B083                                    mov al,83h                      ; Enable DLAB
 1369 0000059D E83908                                  call slow_out
 1370 000005A0 58                                      pop ax                          ; Divisor
 1371 000005A1 89DA                                    mov dx,bx
 1372 000005A3 E83308                                  call slow_out
 1373 000005A6 42                                      inc dx
 1374 000005A7 88E0                                    mov al,ah
 1375 000005A9 E82D08                                  call slow_out
 1376 000005AC B003                                    mov al,03h                      ; Disable DLAB
 1377 000005AE 83C202                                  add dx,byte 2
 1378 000005B1 E82508                                  call slow_out
 1379 000005B4 83EA02                                  sub dx,byte 2
 1380 000005B7 30C0                                    xor al,al                       ; IRQ disable
 1381 000005B9 E81D08                                  call slow_out
 1382
 1383                                                  ; Show some life
 1384 000005BC BE[0002]                                mov si,syslinux_banner
 1385 000005BF E87E0B                                  call write_serial_str
 1386 000005C2 BE[6914]                                mov si,copyright_str
 1387 000005C5 E8780B                                  call write_serial_str
 1388
 1389 000005C8 EB6F                                    jmp short parse_config_3
 1390
 1391 000005CA 80EC31                  pc_fkey:        sub ah,'1'
 1392 000005CD 7302                                    jnb pc_fkey1
 1393 000005CF B409                                    mov ah,9                        ; F10
 1394 000005D1 31C9                    pc_fkey1:       xor cx,cx
 1395 000005D3 88E1                                    mov cl,ah
 1396 000005D5 51                                      push cx
 1397 000005D6 B80100                                  mov ax,1
 1398 000005D9 D3E0                                    shl ax,cl
 1399 000005DB 0906[C018]                              or [FKeyMap], ax                ; Mark that we have this loaded
 1400 000005DF BF0010                                  mov di,trackbuf
 1401 000005E2 57                                      push di
 1402 000005E3 E8790D                                  call getline                    ; Get filename to display
 1403 000005E6 5E                                      pop si
 1404 000005E7 5F                                      pop di
 1405 000005E8 C1E704                                  shl di,4                        ; Multiply number by 16
 1406 000005EB 81C70064                                add di,FKeyName
 1407 000005EF E8AA0D                                  call mangle_name                ; Mangle file name
 1408 000005F2 EB45                                    jmp short parse_config_3
 1409
 1410 000005F4 E85800                  pc_label:       call commit_vk                  ; Commit any current vkernel
 1411 000005F7 BF0010                                  mov di,trackbuf                 ; Get virtual filename
 1412 000005FA 57                                      push di
 1413 000005FB E8610D                                  call getline
 1414 000005FE 5E                                      pop si
 1415 000005FF BF0060                                  mov di,VKernelBuf+vk_vname
 1416 00000602 E8970D                                  call mangle_name                ; Mangle virtual name
 1417 00000605 FF06[C618]                              inc word [VKernelCtr]           ; One more vkernel
 1418 00000609 BE0060                                  mov si,VKernelBuf+vk_vname      ; By default, rname == vname
 1419 0000060C BF0B60                                  mov di,VKernelBuf+vk_rname
 1420 0000060F B90B00                                  mov cx,11
 1421 00000612 F3A4                                    rep movsb
 1422 00000614 BE0062                                  mov si,AppendBuf                ; Default append==global append
 1423 00000617 BF1860                                  mov di,VKernelBuf+vk_append
 1424 0000061A 8B0E[BC18]                              mov cx,[AppendLen]
 1425 0000061E 890E1660                                mov [VKernelBuf+vk_appendlen],cx
 1426 00000622 F3A4                                    rep movsb
 1427 00000624 E91200                                  jmp near parse_config_3
 1428
 1429 00000627 E81200                  pc_font:        call pc_getfile                 ; "font" command
 1430 0000062A 740D                                    jz parse_config_3               ; File not found?
 1431 0000062C E88A09                                  call loadfont                   ; Load and install font
 1432 0000062F EB08                                    jmp short parse_config_3
 1433
 1434 00000631 E80800                  pc_kbd:         call pc_getfile                 ; "kbd" command
 1435 00000634 7403                                    jz parse_config_3
 1436 00000636 E8BF09                                  call loadkeys
 1437 00000639 E937FE                  parse_config_3: jmp parse_config
 1438
 1439                                  ;
 1440                                  ; pc_getfile:   For command line options that take file argument, this
 1441                                  ;               routine decodes the file argument and runs it through searchdir
 1442                                  ;
 1443 0000063C BF0010                  pc_getfile:     mov di,trackbuf
 1444 0000063F 57                                      push di
 1445 00000640 E81C0D                                  call getline
 1446 00000643 5E                                      pop si
 1447 00000644 BF2565                                  mov di,MNameBuf
 1448 00000647 57                                      push di
 1449 00000648 E8510D                                  call mangle_name
 1450 0000064B 5F                                      pop di
 1451 0000064C E9CC08                                  jmp searchdir                   ; Tailcall
 1452
 1453                                  ;
 1454                                  ; commit_vk: Store the current VKernelBuf into buffer segment
 1455                                  ;
 1456                                  commit_vk:
 1457 0000064F 833E[C618]00                            cmp word [VKernelCtr],byte 0
 1458 00000654 741F                                    je cvk_ret                      ; No VKernel = return
 1459 00000656 813E[C618]8000                          cmp word [VKernelCtr],max_vk    ; Above limit?
 1460 0000065C 7718                                    ja cvk_overflow
 1461 0000065E 8B3E[C618]                              mov di,[VKernelCtr]
 1462 00000662 4F                                      dec di
 1463 00000663 C1E709                                  shl di,vk_shift
 1464 00000666 BE0060                                  mov si,VKernelBuf
 1465 00000669 B98000                                  mov cx,(vk_size >> 2)
 1466 0000066C 06                                      push es
 1467 0000066D 680080                                  push word vk_seg
 1468 00000670 07                                      pop es
 1469 00000671 F366A5                                  rep movsd                       ; Copy to buffer segment
 1470 00000674 07                                      pop es
 1471 00000675 C3                      cvk_ret:        ret
 1472 00000676 C706[C618]8000          cvk_overflow:   mov word [VKernelCtr],max_vk    ; No more than max_vk, please
 1473 0000067C C3                                      ret
 1474
 1475                                  ;
 1476                                  ; End of configuration file
 1477                                  ;
 1478                                  end_config_file:
 1479 0000067D E8CFFF                                  call commit_vk                  ; Commit any current vkernel
 1480                                  no_config_file:
 1481                                  ;
 1482                                  ; Check whether or not we are supposed to display the boot prompt.
 1483                                  ;
 1484                                  check_for_key:
 1485 00000680 833E[C818]00                            cmp word [ForcePrompt],byte 0   ; Force prompt?
 1486 00000685 7509                                    jnz enter_command
 1487 00000687 F60621655B                              test byte [KbdFlags],5Bh        ; Caps, Scroll, Shift, Alt
 1488 0000068C 0F84EC00                                jz near auto_boot               ; If neither, default boot
 1489
 1490                                  enter_command:
 1491 00000690 BE[9314]                                mov si,boot_prompt
 1492 00000693 E8C20A                                  call cwritestr
 1493
 1494 00000696 C606246500                              mov byte [FuncFlag],0           ; <Ctrl-F> not pressed
 1495 0000069B BF[E418]                                mov di,command_line
 1496                                  ;
 1497                                  ; get the very first character -- we can either time
 1498                                  ; out, or receive a character press at this time.  Some dorky BIOSes stuff
 1499                                  ; a return in the buffer on bootup, so wipe the keyboard buffer first.
 1500                                  ;
 1501 0000069E B401                    clear_buffer:   mov ah,1                        ; Check for pending char
 1502 000006A0 CD16                                    int 16h
 1503 000006A2 7406                                    jz get_char_time
 1504 000006A4 31C0                                    xor ax,ax                       ; Get char
 1505 000006A6 CD16                                    int 16h
 1506 000006A8 EBF4                                    jmp short clear_buffer
 1507 000006AA 8B0E[BE18]              get_char_time:  mov cx,[KbdTimeOut]
 1508 000006AE 21C9                                    and cx,cx
 1509 000006B0 7419                                    jz get_char                     ; Timeout == 0 -> no timeout
 1510 000006B2 41                                      inc cx                          ; The first loop will happen
 1511                                                                                  ; immediately as we don't
 1512                                                                                  ; know the appropriate DX value
 1513 000006B3 51                      time_loop:      push cx
 1514 000006B4 52                      tick_loop:      push dx
 1515 000006B5 E8AD0A                                  call pollchar
 1516 000006B8 750F                                    jnz get_char_pop
 1517 000006BA 31C0                                    xor ax,ax
 1518 000006BC CD1A                                    int 1Ah                         ; Get time "of day"
 1519 000006BE 58                                      pop ax
 1520 000006BF 39C2                                    cmp dx,ax                       ; Has the timer advanced?
 1521 000006C1 74F1                                    je tick_loop
 1522 000006C3 59                                      pop cx
 1523 000006C4 E2ED                                    loop time_loop                  ; If so, decrement counter
 1524 000006C6 E9C100                                  jmp command_done                ; Timeout!
 1525
 1526 000006C9 6658                    get_char_pop:   pop eax                         ; Clear stack
 1527 000006CB E8AE0A                  get_char:       call getchar
 1528 000006CE 20C0                                    and al,al
 1529 000006D0 7462                                    jz func_key
 1530
 1531 000006D2 3C7F                    got_ascii:      cmp al,7Fh                      ; <DEL> == <BS>
 1532 000006D4 743F                                    je backspace
 1533 000006D6 3C20                                    cmp al,' '                      ; ASCII?
 1534 000006D8 722A                                    jb not_ascii
 1535 000006DA 7706                                    ja enter_char
 1536 000006DC 81FF[E418]                              cmp di,command_line             ; Space must not be first
 1537 000006E0 74E9                                    je get_char
 1538 000006E2 F606246501              enter_char:     test byte [FuncFlag],1
 1539 000006E7 740F                                    jz .not_ctrl_f
 1540 000006E9 C606246500                              mov byte [FuncFlag],0
 1541 000006EE 3C30                                    cmp al,'0'
 1542 000006F0 7206                                    jb .not_ctrl_f
 1543 000006F2 7437                                    je ctrl_f_0
 1544 000006F4 3C39                                    cmp al,'9'
 1545 000006F6 7635                                    jbe ctrl_f
 1546 000006F8 81FF[E319]              .not_ctrl_f:    cmp di,max_cmd_len+command_line ; Check there's space
 1547 000006FC 73CD                                    jnb get_char
 1548 000006FE AA                                      stosb                           ; Save it
 1549 000006FF E8490A                                  call writechr                   ; Echo to screen
 1550 00000702 EBC7                    get_char_2:     jmp short get_char
 1551 00000704 C606246500              not_ascii:      mov byte [FuncFlag],0
 1552 00000709 3C0D                                    cmp al,0Dh                      ; Enter
 1553 0000070B 747D                                    je command_done
 1554 0000070D 3C06                                    cmp al,06h                      ; <Ctrl-F>
 1555 0000070F 7413                                    je set_func_flag
 1556 00000711 3C08                                    cmp al,08h                      ; Backspace
 1557 00000713 75B6                                    jne get_char
 1558 00000715 81FF[E418]              backspace:      cmp di,command_line             ; Make sure there is anything
 1559 00000719 74B0                                    je get_char                     ; to erase
 1560 0000071B 4F                                      dec di                          ; Unstore one character
 1561 0000071C BE[9A14]                                mov si,wipe_char                ; and erase it from the screen
 1562 0000071F E8360A                                  call cwritestr
 1563 00000722 EBDE                                    jmp short get_char_2
 1564
 1565                                  set_func_flag:
 1566 00000724 C606246501                              mov byte [FuncFlag],1
 1567 00000729 EBD7                                    jmp short get_char_2
 1568
 1569 0000072B 040A                    ctrl_f_0:       add al,10                       ; <Ctrl-F>0 == F10
 1570 0000072D 57                      ctrl_f:         push di
 1571 0000072E 2C31                                    sub al,'1'
 1572 00000730 30E4                                    xor ah,ah
 1573 00000732 EB0E                                    jmp short show_help
 1574
 1575                                  func_key:
 1576 00000734 57                                      push di
 1577 00000735 80FC44                                  cmp ah,68                       ; F10
 1578 00000738 77C8                                    ja get_char_2
 1579 0000073A 80EC3B                                  sub ah,59                       ; F1
 1580 0000073D 72C3                                    jb get_char_2
 1581 0000073F C1E808                                  shr ax,8
 1582                                  show_help:      ; AX = func key # (0 = F1, 9 = F10)
 1583 00000742 88C1                                    mov cl,al
 1584 00000744 C1E004                                  shl ax,4                        ; Convert to x16
 1585 00000747 BB0100                                  mov bx,1
 1586 0000074A D3E3                                    shl bx,cl
 1587 0000074C 231E[C018]                              and bx,[FKeyMap]
 1588 00000750 74B0                                    jz get_char_2                   ; Undefined F-key
 1589 00000752 89C7                                    mov di,ax
 1590 00000754 81C70064                                add di,FKeyName
 1591 00000758 E8C007                                  call searchdir
 1592 0000075B 7405                                    jz fk_nofile
 1593 0000075D E8B708                                  call get_msg_file
 1594 00000760 EB06                                    jmp short fk_wrcmd
 1595                                  fk_nofile:
 1596 00000762 BE[6418]                                mov si,crlf_msg
 1597 00000765 E8F009                                  call cwritestr
 1598                                  fk_wrcmd:
 1599 00000768 BE[9314]                                mov si,boot_prompt
 1600 0000076B E8EA09                                  call cwritestr
 1601 0000076E 5F                                      pop di                          ; Command line write pointer
 1602 0000076F 57                                      push di
 1603 00000770 C60500                                  mov byte [di],0                 ; Null-terminate command line
 1604 00000773 BE[E418]                                mov si,command_line
 1605 00000776 E8DF09                                  call cwritestr                  ; Write command line so far
 1606 00000779 5F                                      pop di
 1607 0000077A EB86                                    jmp short get_char_2
 1608                                  auto_boot:
 1609 0000077C BE[E519]                                mov si,default_cmd
 1610 0000077F BF[E418]                                mov di,command_line
 1611 00000782 B94000                                  mov cx,(max_cmd_len+4) >> 2
 1612 00000785 F366A5                                  rep movsd
 1613 00000788 EB0F                                    jmp short load_kernel
 1614                                  command_done:
 1615 0000078A BE[6418]                                mov si,crlf_msg
 1616 0000078D E8C809                                  call cwritestr
 1617 00000790 81FF[E418]                              cmp di,command_line             ; Did we just hit return?
 1618 00000794 74E6                                    je auto_boot
 1619 00000796 30C0                                    xor al,al                       ; Store a final null
 1620 00000798 AA                                      stosb
 1621
 1622                                  load_kernel:                                    ; Load the kernel now
 1623                                  ;
 1624                                  ; First we need to mangle the kernel name the way DOS would...
 1625                                  ;
 1626 00000799 BE[E418]                                mov si,command_line
 1627 0000079C BFD064                                  mov di,KernelName
 1628 0000079F 56                                      push si
 1629 000007A0 57                                      push di
 1630 000007A1 E8F80B                                  call mangle_name
 1631 000007A4 5F                                      pop di
 1632 000007A5 5E                                      pop si
 1633                                  ;
 1634                                  ; Fast-forward to first option (we start over from the beginning, since
 1635                                  ; mangle_name doesn't necessarily return a consistent ending state.)
 1636                                  ;
 1637 000007A6 AC                      clin_non_wsp:   lodsb
 1638 000007A7 3C20                                    cmp al,' '
 1639 000007A9 77FB                                    ja clin_non_wsp
 1640 000007AB 20C0                    clin_is_wsp:    and al,al
 1641 000007AD 7405                                    jz clin_opt_ptr
 1642 000007AF AC                                      lodsb
 1643 000007B0 3C20                                    cmp al,' '
 1644 000007B2 76F7                                    jbe clin_is_wsp
 1645 000007B4 4E                      clin_opt_ptr:   dec si                          ; Point to first nonblank
 1646 000007B5 89360C65                                mov [CmdOptPtr],si              ; Save ptr to first option
 1647                                  ;
 1648                                  ; Now check if it is a "virtual kernel"
 1649                                  ;
 1650 000007B9 8B0E[C618]                              mov cx,[VKernelCtr]
 1651 000007BD 1E                                      push ds
 1652 000007BE 680080                                  push word vk_seg
 1653 000007C1 1F                                      pop ds
 1654 000007C2 83F900                                  cmp cx,byte 0
 1655 000007C5 7413                                    je not_vk
 1656 000007C7 31F6                                    xor si,si                       ; Point to first vkernel
 1657 000007C9 60                      vk_check:       pusha
 1658 000007CA B90B00                                  mov cx,11
 1659 000007CD F3A6                                    repe cmpsb                      ; Is this it?
 1660 000007CF 0F847700                                je near vk_found
 1661 000007D3 61                                      popa
 1662 000007D4 81C60002                                add si,vk_size
 1663 000007D8 E2EF                                    loop vk_check
 1664 000007DA 1F                      not_vk:         pop ds
 1665                                  ;
 1666                                  ; Not a "virtual kernel" - check that's OK and construct the command line
 1667                                  ;
 1668 000007DB 833E[CA18]00                            cmp word [AllowImplicit],byte 0
 1669 000007E0 745D                                    je bad_implicit
 1670 000007E2 06                                      push es
 1671 000007E3 56                                      push si
 1672 000007E4 57                                      push di
 1673 000007E5 BF0090                                  mov di,real_mode_seg
 1674 000007E8 8EC7                                    mov es,di
 1675 000007EA BE0062                                  mov si,AppendBuf
 1676 000007ED BF0080                                  mov di,cmd_line_here
 1677 000007F0 8B0E[BC18]                              mov cx,[AppendLen]
 1678 000007F4 F3A4                                    rep movsb
 1679 000007F6 893E[C218]                              mov [CmdLinePtr],di
 1680 000007FA 5F                                      pop di
 1681 000007FB 5E                                      pop si
 1682 000007FC 07                                      pop es
 1683 000007FD BB1000                                  mov bx,exten_count << 2         ; Alternates to try
 1684                                  ;
 1685                                  ; Find the kernel on disk
 1686                                  ;
 1687 00000800 C606DB6400              get_kernel:     mov byte [KernelName+11],0      ; Zero-terminate filename/extension
 1688 00000805 66A1D864                                mov eax,[KernelName+8]          ; Save initial extension
 1689 00000809 66A3[A818]                              mov [OrigKernelExt],eax
 1690 0000080D 53                      .search_loop:   push bx
 1691 0000080E BFD064                                  mov di,KernelName               ; Search on disk
 1692 00000811 E80707                                  call searchdir
 1693 00000814 5B                                      pop bx
 1694 00000815 756C                                    jnz kernel_good
 1695 00000817 668B87[A818]                            mov eax,[exten_table+bx]        ; Try a different extension
 1696 0000081C 66A3D864                                mov [KernelName+8],eax
 1697 00000820 83EB04                                  sub bx,byte 4
 1698 00000823 73E8                                    jnb .search_loop
 1699                                  bad_kernel:
 1700 00000825 BED064                                  mov si,KernelName
 1701 00000828 BF3B65                                  mov di,KernelCName
 1702 0000082B 57                                      push di
 1703 0000082C E8C90B                                  call unmangle_name              ; Get human form
 1704 0000082F BE[9E14]                                mov si,err_notfound             ; Complain about missing kernel
 1705 00000832 E82309                                  call cwritestr
 1706 00000835 5E                                      pop si                          ; KernelCName
 1707 00000836 E81F09                                  call cwritestr
 1708 00000839 BE[6418]                                mov si,crlf_msg
 1709 0000083C E9C706                                  jmp abort_load                  ; Ask user for clue
 1710                                  ;
 1711                                  ; bad_implicit: The user entered a nonvirtual kernel name, with "implicit 0"
 1712                                  ;
 1713 0000083F BED064                  bad_implicit:   mov si,KernelName               ; For the error message
 1714 00000842 BF3B65                                  mov di,KernelCName
 1715 00000845 E8B00B                                  call unmangle_name
 1716 00000848 EBDB                                    jmp short bad_kernel
 1717                                  ;
 1718                                  ; vk_found: We *are* using a "virtual kernel"
 1719                                  ;
 1720 0000084A 61                      vk_found:       popa
 1721 0000084B 57                                      push di
 1722 0000084C BF0060                                  mov di,VKernelBuf
 1723 0000084F B98000                                  mov cx,vk_size >> 2
 1724 00000852 F366A5                                  rep movsd
 1725 00000855 06                                      push es                         ; Restore old DS
 1726 00000856 1F                                      pop ds
 1727 00000857 06                                      push es
 1728 00000858 680090                                  push word real_mode_seg
 1729 0000085B 07                                      pop es
 1730 0000085C BF0080                                  mov di,cmd_line_here
 1731 0000085F BE1860                                  mov si,VKernelBuf+vk_append
 1732 00000862 8B0E1660                                mov cx,[VKernelBuf+vk_appendlen]
 1733 00000866 F3A4                                    rep movsb
 1734 00000868 893E[C218]                              mov [CmdLinePtr],di             ; Where to add rest of cmd
 1735 0000086C 07                                      pop es
 1736 0000086D 5F                                      pop di                          ; DI -> KernelName
 1737 0000086E 57                                      push di
 1738 0000086F BE0B60                                  mov si,VKernelBuf+vk_rname
 1739 00000872 B90B00                                  mov cx,11                       ; We need ECX == CX later
 1740 00000875 F3A4                                    rep movsb
 1741 00000877 5F                                      pop di
 1742 00000878 31DB                                    xor bx,bx                       ; Try only one version
 1743 0000087A E983FF                                  jmp get_kernel
 1744                                  ;
 1745                                  ; kernel_corrupt: Called if the kernel file does not seem healthy
 1746                                  ;
 1747 0000087D BE[BC14]                kernel_corrupt: mov si,err_notkernel
 1748 00000880 E98306                                  jmp abort_load
 1749                                  ;
 1750                                  ; This is it!  We have a name (and location on the disk)... let's load
 1751                                  ; that sucker!!  First we have to decide what kind of file this is; base
 1752                                  ; that decision on the file extension.  The following extensions are
 1753                                  ; recognized:
 1754                                  ;
 1755                                  ; .COM  - COMBOOT image
 1756                                  ; .CBT  - COMBOOT image
 1757                                  ; .BS   - Boot sector
 1758                                  ; .BSS  - Boot sector, but transfer over DOS superblock
 1759                                  ;
 1760                                  ; Anything else is assumed to be a Linux kernel.
 1761                                  ;
 1762                                  kernel_good:
 1763 00000883 60                                      pusha
 1764 00000884 BED064                                  mov si,KernelName
 1765 00000887 BF3B65                                  mov di,KernelCName
 1766 0000088A E86B0B                                  call unmangle_name              ; Get human form
 1767 0000088D 81EF3B65                                sub di,KernelCName
 1768 00000891 893E0E65                                mov [KernelCNameLen],di
 1769 00000895 61                                      popa
 1770
 1771 00000896 668B0ED864                              mov ecx,[KernelName+8]          ; Get (mangled) extension
 1772 0000089B 6681F9434F4D00                          cmp ecx,'COM'
 1773 000008A2 0F84A903                                je near is_comboot_image
 1774 000008A6 6681F943425400                          cmp ecx,'CBT'
 1775 000008AD 0F849E03                                je near is_comboot_image
 1776 000008B1 6681F942532000                          cmp ecx,'BS '
 1777 000008B8 0F844504                                je near is_bootsector
 1778 000008BC 6681F942535300                          cmp ecx,'BSS'
 1779 000008C3 0F843F04                                je near is_bss_sector
 1780                                                  ; Otherwise Linux kernel
 1781                                  ;
 1782                                  ; A Linux kernel consists of three parts: boot sector, setup code, and
 1783                                  ; kernel code.  The boot sector is never executed when using an external
 1784                                  ; booting utility, but it contains some status bytes that are necessary.
 1785                                  ; The boot sector and setup code together form exactly 5 sectors that
 1786                                  ; should be loaded at 9000:0.  The subsequent code should be loaded
 1787                                  ; at 1000:0.  For simplicity, we load the whole thing at 0F60:0, and
 1788                                  ; copy the latter stuff afterwards.
 1789                                  ;
 1790                                  ; NOTE: In the previous code I have avoided making any assumptions regarding
 1791                                  ; the size of a sector, in case this concept ever gets extended to other
 1792                                  ; media like CD-ROM (not that a CD-ROM would be bloody likely to use a FAT
 1793                                  ; filesystem, of course).  However, a "sector" when it comes to Linux booting
 1794                                  ; stuff means 512 bytes *no matter what*, so here I am using that piece
 1795                                  ; of knowledge.
 1796                                  ;
 1797                                  ; First check that our kernel is at least 64K and less than 8M (if it is
 1798                                  ; more than 8M, we need to change the logic for loading it anyway...)
 1799                                  ;
 1800                                  is_linux_kernel:
 1801 000008C7 81FA8000                                cmp dx,80h                      ; 8 megs
 1802 000008CB 77B0                                    ja kernel_corrupt
 1803 000008CD 21D2                                    and dx,dx
 1804 000008CF 74AC                                    jz kernel_corrupt
 1805 000008D1 50                      kernel_sane:    push ax
 1806 000008D2 52                                      push dx
 1807 000008D3 56                                      push si
 1808 000008D4 BE[4F18]                                mov si,loading_msg
 1809 000008D7 E87E08                                  call cwritestr
 1810                                  ;
 1811                                  ; Now start transferring the kernel
 1812                                  ;
 1813 000008DA 680090                                  push word real_mode_seg
 1814 000008DD 07                                      pop es
 1815
 1816 000008DE 50                                      push ax
 1817 000008DF 52                                      push dx
 1818 000008E0 F736F264                                div word [ClustSize]            ; # of clusters total
 1819 000008E4 21D2                                    and dx,dx                       ; Round up
 1820 000008E6 0F95C2                                  setnz dl
 1821 000008E9 0FB6D2                                  movzx dx,dl
 1822 000008EC 01D0                                    add ax,dx
 1823 000008EE A30065                                  mov [KernelClust],ax
 1824 000008F1 5A                                      pop dx
 1825 000008F2 58                                      pop ax
 1826 000008F3 A3CC64                                  mov [KernelSize],ax
 1827 000008F6 8916CE64                                mov [KernelSize+2],dx
 1828                                  ;
 1829                                  ; Now, if we transfer these straight, we'll hit 64K boundaries.  Hence we
 1830                                  ; have to see if we're loading more than 64K, and if so, load it step by
 1831                                  ; step.
 1832                                  ;
 1833 000008FA BA0100                                  mov dx,1                        ; 10000h
 1834 000008FD 31C0                                    xor ax,ax
 1835 000008FF F736F264                                div word [ClustSize]
 1836 00000903 A30465                                  mov [ClustPerMoby],ax           ; Clusters/64K
 1837                                  ;
 1838                                  ; Start by loading the bootsector/setup code, to see if we need to
 1839                                  ; do something funky.  It should fit in the first 32K (loading 64K won't
 1840                                  ; work since we might have funny stuff up near the end of memory).
 1841                                  ; If we have larger than 32K clusters, yes, we're hosed.
 1842                                  ;
 1843 00000906 E8E905                                  call abort_check                ; Check for abort key
 1844 00000909 8B0E0465                                mov cx,[ClustPerMoby]
 1845 0000090D D1E9                                    shr cx,1                        ; Half a moby
 1846 0000090F 290E0065                                sub [KernelClust],cx
 1847 00000913 31DB                                    xor bx,bx
 1848 00000915 5E                                      pop si                          ; Cluster pointer on stack
 1849 00000916 E80DFA                                  call getfssec
 1850 00000919 0F8260FF                                jc near kernel_corrupt          ; Failure in first 32K
 1851 0000091D 26813EFE0155AA                          cmp word [es:bs_bootsign],0AA55h
 1852 00000924 0F8555FF                                jne near kernel_corrupt         ; Boot sec signature missing
 1853                                  ;
 1854                                  ; Get the BIOS' idea of what the size of high memory is
 1855                                  ;
 1856 00000928 56                                      push si                         ; Save our cluster pointer!
 1857
 1858 00000929 B801E8                                  mov ax,0e801h                   ; Query high memory (semi-recent)
 1859 0000092C CD15                                    int 15h
 1860 0000092E 7215                                    jc no_e801
 1861 00000930 3D003C                                  cmp ax,3c00h
 1862 00000933 7710                                    ja no_e801                      ; > 3C00h something's wrong with this call
 1863 00000935 721A                                    jb e801_hole                    ; If memory hole we can only use low part
 1864
 1865 00000937 89D8                                    mov ax,bx
 1866 00000939 66C1E010                                shl eax,16                      ; 64K chunks
 1867 0000093D 660500000001                            add eax,(16 << 20)              ; Add first 16M
 1868 00000943 EB1C                                    jmp short got_highmem
 1869
 1870                                  no_e801:
 1871 00000945 B488                                    mov ah,88h                      ; Query high memory (oldest)
 1872 00000947 CD15                                    int 15h
 1873 00000949 3D0038                                  cmp ax,14*1024                  ; Don't trust memory >15M
 1874 0000094C 7603                                    jna e801_hole
 1875 0000094E B80038                                  mov ax,14*1024
 1876                                  e801_hole:
 1877 00000951 6625FFFF0000                            and eax,0ffffh
 1878 00000957 66C1E00A                                shl eax,10                      ; Convert from kilobytes
 1879 0000095B 660500001000                            add eax,(1 << 20)               ; First megabyte
 1880                                  got_highmem:
 1881 00000961 66A3C864                                mov [HighMemSize],eax
 1882                                  ;
 1883                                  ; Construct the command line (append options have already been copied)
 1884                                  ;
 1885 00000965 26C70620003FA3                          mov word [es:kern_cmd_magic],0A33Fh     ; Command line magic no
 1886 0000096C 26C70622000080                          mov word [es:kern_cmd_offset],cmd_line_here
 1887 00000973 8B3E[C218]                              mov di,[CmdLinePtr]
 1888 00000977 BE[D918]                                mov si,boot_image               ; BOOT_IMAGE=
 1889 0000097A B90B00                                  mov cx,boot_image_len
 1890 0000097D F3A4                                    rep movsb
 1891 0000097F BE3B65                                  mov si,KernelCName              ; Unmangled kernel name
 1892 00000982 8B0E0E65                                mov cx,[KernelCNameLen]
 1893 00000986 F3A4                                    rep movsb
 1894 00000988 B020                                    mov al,' '                      ; Space
 1895 0000098A AA                                      stosb
 1896 0000098B 8B360C65                                mov si,[CmdOptPtr]              ; Options from user input
 1897 0000098F B98100                                  mov cx,(kern_cmd_len+3) >> 2
 1898 00000992 F366A5                                  rep movsd
 1899                                  ;
 1900                                  %ifdef debug
 1901                                                  push ds                         ; DEBUG DEBUG DEBUG
 1902                                                  push es
 1903                                                  pop ds
 1904                                                  mov si,offset cmd_line_here
 1905                                                  call cwritestr
 1906                                                  pop ds
 1907                                                  mov si,offset crlf_msg
 1908                                                  call cwritestr
 1909                                  %endif
 1910                                  ;
 1911                                  ; Scan through the command line for anything that looks like we might be
 1912                                  ; interested in.  The original version of this code automatically assumed
 1913                                  ; the first option was BOOT_IMAGE=, but that is no longer certain.
 1914                                  ;
 1915 00000995 BE0080                                  mov si,cmd_line_here
 1916 00000998 C606[C418]00                            mov byte [initrd_flag],0
 1917 0000099D 06                                      push es                         ; Set DS <- real_mode_seg
 1918 0000099E 1F                                      pop ds
 1919 0000099F AC                      get_next_opt:   lodsb
 1920 000009A0 20C0                                    and al,al
 1921 000009A2 0F848A00                                jz near cmdline_end
 1922 000009A6 3C20                                    cmp al,' '
 1923 000009A8 76F5                                    jbe get_next_opt
 1924 000009AA 4E                                      dec si
 1925 000009AB 668B04                                  mov eax,[si]
 1926 000009AE 663D7667613D                            cmp eax,'vga='
 1927 000009B4 7432                                    je is_vga_cmd
 1928 000009B6 663D6D656D3D                            cmp eax,'mem='
 1929 000009BC 7462                                    je is_mem_cmd
 1930 000009BE 06                                      push es                         ; Save ES -> real_mode_seg
 1931 000009BF 16                                      push ss
 1932 000009C0 07                                      pop es                          ; Set ES <- normal DS
 1933 000009C1 BF[7518]                                mov di,initrd_cmd
 1934 000009C4 B90700                                  mov cx,initrd_cmd_len
 1935 000009C7 F3A6                                    repe cmpsb
 1936 000009C9 7514                                    jne not_initrd
 1937 000009CB BF3065                                  mov di,InitRD
 1938 000009CE 56                                      push si                         ; mangle_dir mangles si
 1939 000009CF E8CA09                                  call mangle_name                ; Mangle ramdisk name
 1940 000009D2 5E                                      pop si
 1941 000009D3 26803E306520                            cmp byte [es:InitRD],' '        ; Null filename?
 1942 000009D9 260F9706[C418]                          seta byte [es:initrd_flag]      ; Set flag if not
 1943 000009DF 07                      not_initrd:     pop es                          ; Restore ES -> real_mode_seg
 1944 000009E0 AC                      skip_this_opt:  lodsb                           ; Load from command line
 1945 000009E1 3C20                                    cmp al,' '
 1946 000009E3 77FB                                    ja skip_this_opt
 1947 000009E5 4E                                      dec si
 1948 000009E6 EBB7                                    jmp short get_next_opt
 1949                                  is_vga_cmd:
 1950 000009E8 83C604                                  add si,byte 4
 1951 000009EB 668B04                                  mov eax,[si]
 1952 000009EE BBFFFF                                  mov bx,-1
 1953 000009F1 663D6E6F726D                            cmp eax, 'norm'                 ; vga=normal
 1954 000009F7 7421                                    je vc0
 1955 000009F9 6625FFFFFF00                            and eax,0ffffffh                ; 3 bytes
 1956 000009FF BBFEFF                                  mov bx,-2
 1957 00000A02 663D65787400                            cmp eax, 'ext'                  ; vga=ext
 1958 00000A08 7410                                    je vc0
 1959 00000A0A BBFDFF                                  mov bx,-3
 1960 00000A0D 663D61736B00                            cmp eax, 'ask'                  ; vga=ask
 1961 00000A13 7405                                    je vc0
 1962 00000A15 E8B008                                  call parseint                   ; vga=<number>
 1963 00000A18 72C6                                    jc skip_this_opt                ; Not an integer
 1964 00000A1A 891EFA01                vc0:            mov [bs_vidmode],bx             ; Set video mode
 1965 00000A1E EBC0                                    jmp short skip_this_opt
 1966                                  is_mem_cmd:
 1967 00000A20 83C604                                  add si,byte 4
 1968 00000A23 E8A208                                  call parseint
 1969 00000A26 72B8                                    jc skip_this_opt                ; Not an integer
 1970 00000A28 3666891EC864                            mov [ss:HighMemSize],ebx
 1971 00000A2E EBB0                                    jmp short skip_this_opt
 1972                                  cmdline_end:
 1973 00000A30 16                                      push ss                         ; Restore standard DS
 1974 00000A31 1F                                      pop ds
 1975                                  ;
 1976                                  ; Now check if we have a large kernel, which needs to be loaded high
 1977                                  ;
 1978 00000A32 2666813E0202486472-                     cmp dword [es:su_header],HEADER_ID      ; New setup code ID
 1979 00000A3B 53
 1980 00000A3C 0F85F401                                jne near old_kernel             ; Old kernel, load low
 1981 00000A40 26813E06020002                          cmp word [es:su_version],0200h  ; Setup code version 2.0
 1982 00000A47 0F82E901                                jb near old_kernel              ; Old kernel, load low
 1983 00000A4B 26813E06020102                          cmp word [es:su_version],0201h  ; Version 2.01+?
 1984 00000A52 720D                                    jb new_kernel                   ; If 2.00, skip this step
 1985 00000A54 26C7062402F47F                          mov word [es:su_heapend],linux_stack    ; Set up the heap
 1986 00000A5B 26800E110280                            or byte [es:su_loadflags],80h   ; Let the kernel know we care
 1987                                  ;
 1988                                  ; We definitely have a new-style kernel.  Let the kernel know who we are,
 1989                                  ; and that we are clueful
 1990                                  ;
 1991                                  new_kernel:
 1992 00000A61 26C606100231                            mov byte [es:su_loader],syslinux_id     ; Show some ID
 1993 00000A67 260FB606F101                            movzx ax,byte [es:bs_setupsecs] ; Variable # of setup sectors
 1994 00000A6D A31465                                  mov [SetupSecs],ax
 1995                                  ;
 1996                                  ; Now see if we have an initial RAMdisk; if so, do requisite computation
 1997                                  ;
 1998 00000A70 F606[C418]01                            test byte [initrd_flag],1
 1999 00000A75 7478                                    jz nk_noinitrd
 2000 00000A77 06                                      push es                         ; ES->real_mode_seg
 2001 00000A78 1E                                      push ds
 2002 00000A79 07                                      pop es                          ; We need ES==DS
 2003 00000A7A BE3065                                  mov si,InitRD
 2004 00000A7D BF4865                                  mov di,InitRDCName
 2005 00000A80 E87509                                  call unmangle_name              ; Create human-readable name
 2006 00000A83 81EF4865                                sub di,InitRDCName
 2007 00000A87 893E1065                                mov [InitRDCNameLen],di
 2008 00000A8B BF3065                                  mov di,InitRD
 2009 00000A8E E88A04                                  call searchdir                  ; Look for it in directory
 2010 00000A91 07                                      pop es
 2011 00000A92 7443                                    jz initrd_notthere
 2012 00000A94 8936[C418]                              mov [initrd_ptr],si             ; Save cluster pointer
 2013 00000A98 26A31C02                                mov [es:su_ramdisklen1],ax      ; Ram disk length
 2014 00000A9C 2689161E02                              mov [es:su_ramdisklen2],dx
 2015 00000AA1 F736F264                                div word [ClustSize]
 2016 00000AA5 21D2                                    and dx,dx                       ; Round up
 2017 00000AA7 0F95C2                                  setnz dl
 2018 00000AAA 0FB6D2                                  movzx dx,dl
 2019 00000AAD 01D0                                    add ax,dx
 2020 00000AAF A30265                                  mov [InitRDClust],ax            ; Ramdisk clusters
 2021 00000AB2 668B16C864                              mov edx,[HighMemSize]           ; End of memory
 2022 00000AB7 66B800000038                            mov eax,HIGHMEM_MAX             ; Limit imposed by kernel
 2023 00000ABD 6639C2                                  cmp edx,eax
 2024 00000AC0 7603                                    jna memsize_ok
 2025 00000AC2 6689C2                                  mov edx,eax                     ; Adjust to fit inside limit
 2026                                  memsize_ok:
 2027 00000AC5 26662B161C02                            sub edx,[es:su_ramdisklen]      ; Subtract size of ramdisk
 2028 00000ACB 31D2                                    xor dx,dx                       ; Round down to 64K boundary
 2029 00000ACD 668916C064                              mov [InitRDat],edx              ; Load address
 2030 00000AD2 E89E03                                  call loadinitrd                 ; Load initial ramdisk
 2031 00000AD5 EB18                                    jmp short initrd_end
 2032
 2033                                  initrd_notthere:
 2034 00000AD7 BE[F116]                                mov si,err_noinitrd
 2035 00000ADA E87B06                                  call cwritestr
 2036 00000ADD BE4865                                  mov si,InitRDCName
 2037 00000AE0 E87506                                  call cwritestr
 2038 00000AE3 BE[6418]                                mov si,crlf_msg
 2039 00000AE6 E91D04                                  jmp abort_load
 2040
 2041 00000AE9 BE[1217]                no_high_mem:    mov si,err_nohighmem            ; Error routine
 2042 00000AEC E91704                                  jmp abort_load
 2043                                  ;
 2044                                  ; About to load the kernel.  This is a modern kernel, so use the boot flags
 2045                                  ; we were provided.
 2046                                  ;
 2047                                  nk_noinitrd:
 2048                                  initrd_end:
 2049 00000AEF 26A01102                                mov al,[es:su_loadflags]
 2050 00000AF3 A22265                                  mov [LoadFlags],al
 2051                                  ;
 2052                                  ; Load the kernel.  We always load it at 100000h even if we're supposed to
 2053                                  ; load it "low"; for a "low" load we copy it down to low memory right before
 2054                                  ; jumping to it.
 2055                                  ;
 2056                                  read_kernel:
 2057 00000AF6 BE3B65                                  mov si,KernelCName              ; Print kernel name part of
 2058 00000AF9 E85C06                                  call cwritestr                  ; "Loading" message
 2059 00000AFC BE[5818]                                mov si,dotdot_msg               ; Print dots
 2060 00000AFF E85606                                  call cwritestr
 2061
 2062 00000B02 66A1C864                                mov eax,[HighMemSize]
 2063 00000B06 662D00001000                            sub eax,100000h                 ; Load address
 2064 00000B0C 663B06CC64                              cmp eax,[KernelSize]
 2065 00000B11 72D6                                    jb no_high_mem                  ; Not enough high memory
 2066                                  ;
 2067                                  ; Move the stuff beyond the setup code to high memory at 100000h
 2068                                  ;
 2069 00000B13 660FB7361465                            movzx esi,word [SetupSecs]      ; Setup sectors
 2070 00000B19 6646                                    inc esi                         ; plus 1 boot sector
 2071 00000B1B 66C1E609                                shl esi,9                       ; Convert to bytes
 2072 00000B1F 66B900801000                            mov ecx,108000h                 ; 108000h = 1M + 32K
 2073 00000B25 6629F1                                  sub ecx,esi                     ; Adjust pointer to 2nd block
 2074 00000B28 66890EC464                              mov [HiLoadAddr],ecx
 2075 00000B2D 6681E900001000                          sub ecx,100000h                 ; Turn into a counter
 2076 00000B34 66C1E902                                shr ecx,2                       ; Convert to dwords
 2077 00000B38 6681C600000900                          add esi,90000h                  ; Pointer to source
 2078 00000B3F 66BF00001000                            mov edi,100000h                 ; Copy to address 100000h
 2079 00000B45 E83C02                                  call bcopy                      ; Transfer to high memory
 2080                                  ;
 2081 00000B48 680070                                  push word xfer_buf_seg          ; Segment 7000h is xfer buffer
 2082 00000B4B 07                                      pop es
 2083                                  high_load_loop:
 2084 00000B4C BE[5918]                                mov si,dot_msg                  ; Progress report
 2085 00000B4F E80606                                  call cwritestr
 2086 00000B52 E89D03                                  call abort_check
 2087 00000B55 8B0E0065                                mov cx,[KernelClust]
 2088 00000B59 3B0E0465                                cmp cx,[ClustPerMoby]
 2089 00000B5D 7604                                    jna high_last_moby
 2090 00000B5F 8B0E0465                                mov cx,[ClustPerMoby]
 2091                                  high_last_moby:
 2092 00000B63 290E0065                                sub [KernelClust],cx
 2093 00000B67 31DB                                    xor bx,bx                       ; Load at offset 0
 2094 00000B69 5E                                      pop si                          ; Restore cluster pointer
 2095 00000B6A E8B9F7                                  call getfssec
 2096 00000B6D 56                                      push si                         ; Save cluster pointer
 2097 00000B6E 9C                                      pushf                           ; Save EOF
 2098 00000B6F 31DB                                    xor bx,bx
 2099 00000B71 66BE00000700                            mov esi,(xfer_buf_seg << 4)
 2100 00000B77 668B3EC464                              mov edi,[HiLoadAddr]            ; Destination address
 2101 00000B7C 66B900400000                            mov ecx,4000h                   ; Cheating - transfer 64K
 2102 00000B82 E8FF01                                  call bcopy                      ; Transfer to high memory
 2103 00000B85 66893EC464                              mov [HiLoadAddr],edi            ; Point to next target area
 2104 00000B8A 9D                                      popf                            ; Restore EOF
 2105 00000B8B 7207                                    jc high_load_done               ; If EOF we are done
 2106 00000B8D 833E006500                              cmp word [KernelClust],byte 0   ; Are we done?
 2107 00000B92 75B8                                    jne high_load_loop              ; Apparently not
 2108                                  high_load_done:
 2109 00000B94 5E                                      pop si                          ; No longer needed
 2110 00000B95 B80090                                  mov ax,real_mode_seg            ; Set to real mode seg
 2111 00000B98 8EC0                                    mov es,ax
 2112
 2113 00000B9A BE[5918]                                mov si,dot_msg
 2114 00000B9D E8B805                                  call cwritestr
 2115                                  ;
 2116                                  ; Abandon hope, ye that enter here!  We do no longer permit aborts.
 2117                                  ;
 2118 00000BA0 E84F03                                  call abort_check                ; Last chance!!
 2119
 2120                                  ;
 2121                                  ; Some kernels in the 1.2 ballpark but pre-bzImage have more than 4
 2122                                  ; setup sectors, but the boot protocol had not yet been defined.  They
 2123                                  ; rely on a signature to figure out if they need to copy stuff from
 2124                                  ; the "protected mode" kernel area.  Unfortunately, we used that area
 2125                                  ; as a transfer buffer, so it's going to find the signature there.
 2126                                  ; Hence, zero the low 32K beyond the setup area.
 2127                                  ;
 2128 00000BA3 8B3E1465                                mov di,[SetupSecs]
 2129 00000BA7 47                                      inc di                          ; Setup + boot sector
 2130 00000BA8 B94000                                  mov cx,32768/512                ; Sectors/32K
 2131 00000BAB 29F9                                    sub cx,di                       ; Remaining sectors
 2132 00000BAD C1E709                                  shl di,9                        ; Sectors -> bytes
 2133 00000BB0 C1E107                                  shl cx,7                        ; Sectors -> dwords
 2134 00000BB3 6631C0                                  xor eax,eax
 2135 00000BB6 F366AB                                  rep stosd                       ; Clear region
 2136                                  ;
 2137                                  ; Now, if we were supposed to load "low", copy the kernel down to 10000h
 2138                                  ;
 2139 00000BB9 F606226501                              test byte [LoadFlags],LOAD_HIGH
 2140 00000BBE 751F                                    jnz in_proper_place             ; If high load, we're done
 2141
 2142 00000BC0 668B0ECC64                              mov ecx,[KernelSize]
 2143 00000BC5 6681C103000000                          add ecx,3                       ; Round upwards
 2144 00000BCC 66C1E902                                shr ecx,2                       ; Bytes -> dwords
 2145 00000BD0 66BE00001000                            mov esi,100000h
 2146 00000BD6 66BF00000100                            mov edi,10000h
 2147 00000BDC E8A501                                  call bcopy
 2148                                  in_proper_place:
 2149                                  ;
 2150                                  ; If the default root device is set to FLOPPY (0000h), change to
 2151                                  ; /dev/fd0 (0200h)
 2152                                  ;
 2153 00000BDF 26833EFC0100                            cmp word [es:bs_rootdev],byte 0
 2154 00000BE5 7507                                    jne root_not_floppy
 2155 00000BE7 26C706FC010002                          mov word [es:bs_rootdev],0200h
 2156                                  root_not_floppy:
 2157                                  ;
 2158                                  ; Copy the disk table to high memory, then re-initialize the floppy
 2159                                  ; controller
 2160                                  ;
 2161 00000BEE 1E                                      push ds
 2162 00000BEF C5367800                                lds si,[fdctab]
 2163 00000BF3 BFF47F                                  mov di,linux_fdctab
 2164 00000BF6 B90300                                  mov cx,3                        ; 12 bytes
 2165 00000BF9 57                                      push di
 2166 00000BFA F366A5                                  rep movsd
 2167 00000BFD 5F                                      pop di
 2168 00000BFE FA                                      cli
 2169 00000BFF 893E7800                                mov [fdctab1],di                ; Save new floppy tab pos
 2170 00000C03 8C067A00                                mov [fdctab2],es
 2171 00000C07 FB                                      sti
 2172 00000C08 31C0                                    xor ax,ax
 2173 00000C0A 31D2                                    xor dx,dx
 2174 00000C0C CD13                                    int 13h
 2175 00000C0E 1F                                      pop ds
 2176                                  ;
 2177                                  ; Linux wants the floppy motor shut off before starting the kernel,
 2178                                  ; at least bootsect.S seems to imply so
 2179                                  ;
 2180                                  kill_motor:
 2181 00000C0F BAF203                                  mov dx,03F2h
 2182 00000C12 30C0                                    xor al,al
 2183 00000C14 E8C201                                  call slow_out
 2184                                  ;
 2185                                  ; Now we're as close to be done as we can be and still use our normal
 2186                                  ; routines, print a CRLF to end the row of dots
 2187                                  ;
 2188 00000C17 BE[6418]                                mov si,crlf_msg
 2189 00000C1A E83B05                                  call cwritestr
 2190                                  ;
 2191                                  ; If we're debugging, wait for a keypress so we can read any debug messages
 2192                                  ;
 2193                                  %ifdef debug
 2194                                                  xor ax,ax
 2195                                                  int 16h
 2196                                  %endif
 2197                                  ;
 2198                                  ; Set up segment registers and the Linux real-mode stack
 2199                                  ;
 2200 00000C1D B80090                                  mov ax,real_mode_seg
 2201 00000C20 8ED8                                    mov ds,ax
 2202 00000C22 8EC0                                    mov es,ax
 2203 00000C24 8EE0                                    mov fs,ax
 2204 00000C26 8EE8                                    mov gs,ax
 2205 00000C28 FA                                      cli
 2206 00000C29 8ED0                                    mov ss,ax
 2207 00000C2B BCF47F                                  mov sp,linux_stack
 2208 00000C2E FB                                      sti
 2209                                  ;
 2210                                  ; We're done... now RUN THAT KERNEL!!!!
 2211                                  ;
 2212 00000C2F EA00002090                              jmp setup_seg:setup_entry
 2213                                  ;
 2214                                  ; Load an older kernel.  Older kernels always have 4 setup sectors, can't have
 2215                                  ; initrd, and are always loaded low.
 2216                                  ;
 2217                                  old_kernel:
 2218 00000C34 F606[C418]01                            test byte [initrd_flag],1       ; Old kernel can't have initrd
 2219 00000C39 7406                                    jz load_old_kernel
 2220 00000C3B BE[5D17]                                mov si,err_oldkernel
 2221 00000C3E E9C502                                  jmp abort_load
 2222                                  load_old_kernel:
 2223 00000C41 C70614650400                            mov word [SetupSecs],4          ; Always 4 setup sectors
 2224 00000C47 C606226500                              mov byte [LoadFlags],0          ; Always low
 2225 00000C4C E9A7FE                                  jmp read_kernel
 2226
 2227                                  ;
 2228                                  ; Load a COMBOOT image.  A COMBOOT image is basically a DOS .COM file,
 2229                                  ; except that it may, of course, not contain any DOS system calls.  We
 2230                                  ; do, however, allow the execution of INT 20h to return to SYSLINUX.
 2231                                  ;
 2232                                  is_comboot_image:
 2233 00000C4F 21D2                                    and dx,dx
 2234 00000C51 7575                                    jnz comboot_too_large
 2235 00000C53 3D00FF                                  cmp ax,0ff00h           ; Max size in bytes
 2236 00000C56 7370                                    jae comboot_too_large
 2237
 2238                                                  ;
 2239                                                  ; Set up the DOS vectors in the IVT (INT 20h-3fh)
 2240                                                  ;
 2241 00000C58 66C7068000-                             mov dword [4*0x20],comboot_return       ; INT 20h vector
 2242 00000C5D [D10C0000]
 2243 00000C61 66B8[E30C0000]                          mov eax,comboot_bogus
 2244 00000C67 BF8400                                  mov di,4*0x21
 2245 00000C6A B91F00                                  mov cx,31               ; All remaining DOS vectors
 2246 00000C6D F366AB                                  rep stosd
 2247
 2248 00000C70 B90020                                  mov cx,comboot_seg
 2249 00000C73 8EC1                                    mov es,cx
 2250
 2251 00000C75 BB0001                                  mov bx,100h             ; Load at <seg>:0100h
 2252
 2253 00000C78 8B0E0465                                mov cx,[ClustPerMoby]   ; Absolute maximum # of clusters
 2254 00000C7C E8A7F6                                  call getfssec
 2255
 2256 00000C7F 31FF                                    xor di,di
 2257 00000C81 B94000                                  mov cx,64               ; 256 bytes (size of PSP)
 2258 00000C84 6631C0                                  xor eax,eax             ; Clear PSP
 2259 00000C87 F366AB                                  rep stosd
 2260
 2261 00000C8A 26C7060000CD20                          mov word [es:0], 020CDh ; INT 20h instruction
 2262                                                  ; First non-free paragraph
 2263 00000C91 26C70602000030                          mov word [es:02h], comboot_seg+1000h
 2264
 2265                                                  ; Copy the command line from high memory
 2266 00000C98 B97D00                                  mov cx,125              ; Max cmdline len (minus space and CR)
 2267 00000C9B 8B360C65                                mov si,[CmdOptPtr]
 2268 00000C9F BF8100                                  mov di,081h             ; Offset in PSP for command line
 2269 00000CA2 B020                                    mov al,' '              ; DOS command lines begin with a space
 2270 00000CA4 AA                                      stosb
 2271
 2272 00000CA5 AC                      comboot_cmd_cp: lodsb
 2273 00000CA6 20C0                                    and al,al
 2274 00000CA8 7403                                    jz comboot_end_cmd
 2275 00000CAA AA                                      stosb
 2276 00000CAB E2F8                                    loop comboot_cmd_cp
 2277 00000CAD B00D                    comboot_end_cmd: mov al,0Dh             ; CR after last character
 2278 00000CAF AA                                      stosb
 2279 00000CB0 B07E                                    mov al,126              ; Include space but not CR
 2280 00000CB2 28C8                                    sub al,cl
 2281 00000CB4 26A28000                                mov [es:80h], al        ; Store command line length
 2282
 2283 00000CB8 8CC0                                    mov ax,es
 2284 00000CBA 8ED8                                    mov ds,ax
 2285 00000CBC 8ED0                                    mov ss,ax
 2286 00000CBE 31E4                                    xor sp,sp
 2287 00000CC0 680000                                  push word 0             ; Return to address 0 -> exit
 2288
 2289 00000CC3 EA00010020                              jmp comboot_seg:100h    ; Run it
 2290
 2291                                  ; Looks like a COMBOOT image but too large
 2292                                  comboot_too_large:
 2293 00000CC8 BE[AD17]                                mov si,err_comlarge
 2294 00000CCB E88A04                                  call cwritestr
 2295 00000CCE E9BFF9                  cb_enter:       jmp enter_command
 2296
 2297                                  ; Proper return vector
 2298 00000CD1 FA                      comboot_return: cli                     ; Don't trust anyone
 2299 00000CD2 31C0                                    xor ax,ax
 2300 00000CD4 8ED0                                    mov ss,ax
 2301 00000CD6 368B261665                              mov sp,[ss:SavedSP]
 2302 00000CDB 8ED8                                    mov ds,ax
 2303 00000CDD 8EC0                                    mov es,ax
 2304 00000CDF FB                                      sti
 2305 00000CE0 FC                                      cld
 2306 00000CE1 EBEB                                    jmp short cb_enter
 2307
 2308                                  ; Attempted to execute DOS system call
 2309 00000CE3 FA                      comboot_bogus:  cli                     ; Don't trust anyone
 2310 00000CE4 31C0                                    xor ax,ax
 2311 00000CE6 8ED0                                    mov ss,ax
 2312 00000CE8 368B261665                              mov sp,[ss:SavedSP]
 2313 00000CED 8ED8                                    mov ds,ax
 2314 00000CEF 8EC0                                    mov es,ax
 2315 00000CF1 FB                                      sti
 2316 00000CF2 FC                                      cld
 2317 00000CF3 BE3B65                                  mov si,KernelCName
 2318 00000CF6 E85F04                                  call cwritestr
 2319 00000CF9 BE[8F17]                                mov si,err_notdos
 2320 00000CFC E85904                                  call cwritestr
 2321 00000CFF EBCD                                    jmp short cb_enter
 2322
 2323                                  ;
 2324                                  ; Load a boot sector
 2325                                  ;
 2326                                  is_bootsector:
 2327                                                  ; Transfer zero bytes
 2328 00000D01 680000                                  push word 0
 2329 00000D04 EB03                                    jmp short load_bootsec
 2330                                  is_bss_sector:
 2331                                                  ; Transfer the superblock
 2332 00000D06 683300                                  push word superblock_len
 2333                                  load_bootsec:
 2334 00000D09 21D2                                    and dx,dx
 2335 00000D0B 754C                                    jnz bad_bootsec
 2336 00000D0D 8B1E[0B00]                              mov bx,[bsBytesPerSec]
 2337 00000D11 39D8                                    cmp ax,bx
 2338 00000D13 7544                                    jne bad_bootsec
 2339
 2340                                                  ; Make sure we don't test this uninitialized
 2341 00000D15 8997FE0F                                mov [bx+trackbuf-2],dx  ; Note DX == 0
 2342
 2343 00000D19 BB0010                                  mov bx,trackbuf
 2344 00000D1C B90100                                  mov cx,1                ; 1 cluster >= 1 sector
 2345 00000D1F E804F6                                  call getfssec
 2346
 2347 00000D22 8B1E[0B00]                              mov bx,[bsBytesPerSec]
 2348 00000D26 8B87FE0F                                mov ax,[bx+trackbuf-2]
 2349 00000D2A 3D55AA                                  cmp ax,0AA55h           ; Boot sector signature
 2350 00000D2D 752A                                    jne bad_bootsec
 2351
 2352 00000D2F BE[0B00]                                mov si,superblock
 2353 00000D32 BF0B10                                  mov di,trackbuf+(superblock-bootsec)
 2354 00000D35 59                                      pop cx                  ; Transfer count
 2355 00000D36 F3A4                                    rep movsb
 2356                                  ;
 2357                                  ; Okay, here we go... copy over our own boot sector and run the new one
 2358                                  ;
 2359 00000D38 FA                                      cli                     ; Point of no return
 2360
 2361 00000D39 8A16[2400]                              mov dl,[bsDriveNumber]  ; May not be in new bootsector!
 2362
 2363 00000D3D BE0010                                  mov si,trackbuf
 2364 00000D40 BF[0000]                                mov di,bootsec
 2365 00000D43 8B0E[0B00]                              mov cx,[bsBytesPerSec]
 2366 00000D47 F3A4                                    rep movsb               ; Copy the boot sector!
 2367
 2368 00000D49 BEB064                                  mov si,PartInfo
 2369 00000D4C BFEE07                                  mov di,800h-18          ; Put partition info here
 2370 00000D4F 57                                      push di
 2371 00000D50 B90800                                  mov cx,8                ; 16 bytes
 2372 00000D53 F3A5                                    rep movsw
 2373 00000D55 5E                                      pop si                  ; DS:SI points to partition info
 2374
 2375 00000D56 E9A7F2                                  jmp bootsec
 2376
 2377                                  bad_bootsec:
 2378 00000D59 BE[C817]                                mov si,err_bootsec
 2379 00000D5C E8F903                                  call cwritestr
 2380 00000D5F E92EF9                                  jmp enter_command
 2381
 2382                                  ;
 2383                                  ; 32-bit bcopy routine for real mode
 2384                                  ;
 2385                                  ; We enter protected mode, set up a flat 32-bit environment, run rep movsd
 2386                                  ; and then exit.  IMPORTANT: This code assumes cs == ss == 0.
 2387                                  ;
 2388                                  ; This code is probably excessively anal-retentive in its handling of
 2389                                  ; segments, but this stuff is painful enough as it is without having to rely
 2390                                  ; on everything happening "as it ought to."
 2391                                  ;
 2392 00000D62 90<rept>                                align 4
 2393 00000D64 1F00                    bcopy_gdt:      dw bcopy_gdt_size-1     ; Null descriptor - contains GDT
 2394 00000D66 [640D0000]                              dd bcopy_gdt            ; pointer for LGDT instruction
 2395 00000D6A 0000                                    dw 0
 2396 00000D6C FFFF0000                                dd 0000ffffh            ; Code segment, use16, readable,
 2397 00000D70 009B0000                                dd 00009b00h            ; present, dpl 0, cover 64K
 2398 00000D74 FFFF0000                                dd 0000ffffh            ; Data segment, use16, read/write,
 2399 00000D78 00938F00                                dd 008f9300h            ; present, dpl 0, cover all 4G
 2400 00000D7C FFFF0000                                dd 0000ffffh            ; Data segment, use16, read/write,
 2401 00000D80 00930000                                dd 00009300h            ; present, dpl 0, cover 64K
 2402                                  bcopy_gdt_size: equ $-bcopy_gdt
 2403
 2404 00000D84 6650                    bcopy:          push eax
 2405 00000D86 9C                                      pushf                   ; Saves, among others, the IF flag
 2406 00000D87 0FA8                                    push gs
 2407 00000D89 0FA0                                    push fs
 2408 00000D8B 1E                                      push ds
 2409 00000D8C 06                                      push es
 2410
 2411 00000D8D FA                                      cli
 2412 00000D8E E85400                                  call enable_a20
 2413
 2414 00000D91 660F0116[640D]                          o32 lgdt [bcopy_gdt]
 2415 00000D97 0F20C0                                  mov eax,cr0
 2416 00000D9A 0C01                                    or al,1
 2417 00000D9C 0F22C0                                  mov cr0,eax             ; Enter protected mode
 2418 00000D9F EA[A40D]0800                            jmp 08h:.in_pm
 2419
 2420 00000DA4 B81000                  .in_pm:         mov ax,10h              ; Data segment selector
 2421 00000DA7 8EC0                                    mov es,ax
 2422 00000DA9 8ED8                                    mov ds,ax
 2423
 2424 00000DAB B018                                    mov al,18h              ; "Real-mode-like" data segment
 2425 00000DAD 8ED0                                    mov ss,ax
 2426 00000DAF 8EE0                                    mov fs,ax
 2427 00000DB1 8EE8                                    mov gs,ax
 2428
 2429 00000DB3 67F366A5                                a32 rep movsd           ; Do our business
 2430
 2431 00000DB7 8EC0                                    mov es,ax               ; Set to "real-mode-like"
 2432 00000DB9 8ED8                                    mov ds,ax
 2433
 2434 00000DBB 0F20C0                                  mov eax,cr0
 2435 00000DBE 24FE                                    and al,~1
 2436 00000DC0 0F22C0                                  mov cr0,eax             ; Disable protected mode
 2437 00000DC3 EA[C80D]0000                            jmp 0:.in_rm
 2438
 2439 00000DC8 31C0                    .in_rm:         xor ax,ax               ; Back in real mode
 2440 00000DCA 8ED0                                    mov ss,ax
 2441 00000DCC 07                                      pop es
 2442 00000DCD 1F                                      pop ds
 2443 00000DCE 0FA1                                    pop fs
 2444 00000DD0 0FA9                                    pop gs
 2445 00000DD2 E85E00                                  call disable_a20
 2446
 2447 00000DD5 9D                                      popf                    ; Re-enables interrupts
 2448 00000DD6 6658                                    pop eax
 2449 00000DD8 C3                                      ret
 2450
 2451                                  ;
 2452                                  ; Routines to enable and disable (yuck) A20.  These routines are gathered
 2453                                  ; from tips from a couple of sources, including the Linux kernel and
 2454                                  ; http://www.x86.org/.  The need for the delay to be as large as given here
 2455                                  ; is indicated by Donnie Barnes of RedHat, the problematic system being an
 2456                                  ; IBM ThinkPad 760EL.
 2457                                  ;
 2458                                  ; We typically toggle A20 twice for every 64K transferred.
 2459                                  ;
 2460                                  %define io_delay        call _io_delay
 2461                                  %define IO_DELAY_PORT   80h             ; Invalid port (we hope!)
 2462                                  %define delaytime       1024            ; 4 x ISA bus cycles (@ 1.5 �s)
 2463
 2464 00000DD9 EE                      slow_out:       out dx, al              ; Fall through
 2465
 2466 00000DDA 50                      _io_delay:      push ax
 2467 00000DDB E580                                    in ax,IO_DELAY_PORT
 2468 00000DDD E580                                    in ax,IO_DELAY_PORT
 2469 00000DDF E580                                    in ax,IO_DELAY_PORT
 2470 00000DE1 E580                                    in ax,IO_DELAY_PORT
 2471 00000DE3 58                                      pop ax
 2472 00000DE4 C3                                      ret
 2473
 2474                                  enable_a20:
 2475 00000DE5 36C6062365FF                            mov byte [ss:A20Tries],255 ; Times to try to make this work
 2476
 2477                                  try_enable_a20:
 2478                                  ;
 2479                                  ; Flush the caches
 2480                                  ;
 2481 00000DEB E88200                                  call try_wbinvd
 2482
 2483                                  ;
 2484                                  ; Enable the "fast A20 gate"
 2485                                  ;
 2486 00000DEE E492                                    in al, 092h
 2487 00000DF0 0C02                                    or al,02h
 2488 00000DF2 E692                                    out 092h, al
 2489                                  ;
 2490                                  ; Enable the keyboard controller A20 gate
 2491                                  ;
 2492 00000DF4 E86100                                  call empty_8042
 2493 00000DF7 B0D1                                    mov al,0D1h             ; Command write
 2494 00000DF9 E664                                    out 064h, al
 2495 00000DFB E85A00                                  call empty_8042
 2496 00000DFE B0DF                                    mov al,0DFh             ; A20 on
 2497 00000E00 E660                                    out 060h, al
 2498 00000E02 E84500                                  call kbc_delay
 2499                                                  ; Verify that A20 actually is enabled.  Do that by
 2500                                                  ; observing a word in low memory and the same word in
 2501                                                  ; the HMA until they are no longer coherent.  Note that
 2502                                                  ; we don't do the same check in the disable case, because
 2503                                                  ; we don't want to *require* A20 masking (SYSLINUX should
 2504                                                  ; work fine without it, if the BIOS does.)
 2505 00000E05 06                                      push es
 2506 00000E06 51                                      push cx
 2507 00000E07 B9FFFF                                  mov cx,0FFFFh           ; Times to try, also HMA
 2508 00000E0A 8EC1                                    mov es,cx               ; HMA = segment 0FFFFh
 2509 00000E0C 36FF061865              .a20_wait:      inc word [ss:A20Test]
 2510 00000E11 E85C00                                  call try_wbinvd
 2511 00000E14 26A12865                                mov ax,[es:A20Test+10h]
 2512 00000E18 363B061865                              cmp ax,[ss:A20Test]
 2513 00000E1D 7511                                    jne .a20_done
 2514 00000E1F E2EB                                    loop .a20_wait
 2515                                  ;
 2516                                  ; Oh bugger.  A20 is not responding.  Try frobbing it again; eventually give up
 2517                                  ; and report failure to the user.
 2518                                  ;
 2519 00000E21 59                                      pop cx
 2520 00000E22 07                                      pop es
 2521
 2522 00000E23 36FE0E2365                              dec byte [ss:A20Tries]
 2523 00000E28 75C1                                    jnz try_enable_a20
 2524
 2525 00000E2A BE[F017]                                mov si, err_a20
 2526 00000E2D E9D600                                  jmp abort_load
 2527                                  ;
 2528                                  ; A20 unmasked, proceed...
 2529                                  ;
 2530 00000E30 59                      .a20_done:      pop cx
 2531 00000E31 07                                      pop es
 2532 00000E32 C3                                      ret
 2533
 2534                                  disable_a20:
 2535                                  ;
 2536                                  ; Flush the caches
 2537                                  ;
 2538 00000E33 E83A00                                  call try_wbinvd
 2539                                  ;
 2540                                  ; Disable the "fast A20 gate"
 2541                                  ;
 2542 00000E36 E492                                    in al, 092h
 2543 00000E38 24FD                                    and al,~02h
 2544 00000E3A E692                                    out 092h, al
 2545                                  ;
 2546                                  ; Disable the keyboard controller A20 gate
 2547                                  ;
 2548 00000E3C E81900                                  call empty_8042
 2549 00000E3F B0D1                                    mov al,0D1h
 2550 00000E41 E664                                    out 064h, al            ; Command write
 2551 00000E43 E81200                                  call empty_8042
 2552 00000E46 B0DD                                    mov al,0DDh             ; A20 off
 2553 00000E48 E660                                    out 060h, al
 2554                                                  ; Fall through/tailcall to kbc_delay
 2555
 2556 00000E4A E80B00                  kbc_delay:      call empty_8042
 2557 00000E4D 51                                      push cx
 2558 00000E4E B90004                                  mov cx, delaytime
 2559 00000E51 E886FF                  .delayloop:     io_delay
 2560 00000E54 E2FB                                    loop .delayloop
 2561 00000E56 59                                      pop cx
 2562 00000E57 C3                                      ret
 2563
 2564                                  empty_8042:
 2565 00000E58 E87FFF                                  io_delay
 2566 00000E5B E464                                    in al, 064h             ; Status port
 2567 00000E5D A801                                    test al,1
 2568 00000E5F 7407                                    jz .no_output
 2569 00000E61 E876FF                                  io_delay
 2570 00000E64 E460                                    in al, 060h             ; Read input
 2571 00000E66 EBF0                                    jmp short empty_8042
 2572                                  .no_output:
 2573 00000E68 A802                                    test al,2
 2574 00000E6A 75EC                                    jnz empty_8042
 2575 00000E6C E86BFF                                  io_delay
 2576 00000E6F C3                                      ret
 2577
 2578                                  ;
 2579                                  ; WBINVD instruction; gets auto-eliminated on 386 CPUs
 2580                                  ;
 2581                                  try_wbinvd:
 2582 00000E70 0F09                                    wbinvd
 2583 00000E72 C3                                      ret
 2584
 2585                                  ;
 2586                                  ; Load RAM disk into high memory
 2587                                  ;
 2588                                  loadinitrd:
 2589 00000E73 06                                      push es                         ; Save ES on entry
 2590 00000E74 B80090                                  mov ax,real_mode_seg
 2591 00000E77 8EC0                                    mov es,ax
 2592 00000E79 8B36[C418]                              mov si,[initrd_ptr]
 2593 00000E7D 668B3EC064                              mov edi,[InitRDat]              ; initrd load address
 2594 00000E82 2666893E1802                            mov [es:su_ramdiskat],edi       ; Offset for ram disk
 2595 00000E88 56                                      push si
 2596 00000E89 BE4865                                  mov si,InitRDCName              ; Write ramdisk name
 2597 00000E8C E8C902                                  call cwritestr
 2598 00000E8F BE[5818]                                mov si,dotdot_msg               ; Write dots
 2599 00000E92 E8C302                                  call cwritestr
 2600                                  rd_load_loop:
 2601 00000E95 BE[5918]                                mov si,dot_msg                  ; Progress report
 2602 00000E98 E8BD02                                  call cwritestr
 2603 00000E9B 5E                                      pop si                          ; Restore cluster pointer
 2604 00000E9C E85300                                  call abort_check
 2605 00000E9F 8B0E0265                                mov cx,[InitRDClust]
 2606 00000EA3 3B0E0465                                cmp cx,[ClustPerMoby]
 2607 00000EA7 7604                                    jna rd_last_moby
 2608 00000EA9 8B0E0465                                mov cx,[ClustPerMoby]
 2609                                  rd_last_moby:
 2610 00000EAD 290E0265                                sub [InitRDClust],cx
 2611 00000EB1 31DB                                    xor bx,bx                       ; Load at offset 0
 2612 00000EB3 680070                                  push word xfer_buf_seg          ; Bounce buffer segment
 2613 00000EB6 07                                      pop es
 2614 00000EB7 51                                      push cx
 2615 00000EB8 E86BF4                                  call getfssec
 2616 00000EBB 59                                      pop cx
 2617 00000EBC 56                                      push si                         ; Save cluster pointer
 2618 00000EBD 66BE00000700                            mov esi,(xfer_buf_seg << 4)
 2619 00000EC3 668B3EC064                              mov edi,[InitRDat]
 2620 00000EC8 66B900400000                            mov ecx,4000h                   ; Copy 64K
 2621 00000ECE E8B3FE                                  call bcopy                      ; Does not change flags!!
 2622 00000ED1 7210                                    jc rd_load_done                 ; EOF?
 2623 00000ED3 668106C06400000100                      add dword [InitRDat],10000h     ; Point to next 64K
 2624 00000EDC 833E026500                              cmp word [InitRDClust],byte 0   ; Are we done?
 2625 00000EE1 75B2                                    jne rd_load_loop                ; Apparently not
 2626                                  rd_load_done:
 2627 00000EE3 5E                                      pop si                          ; Clean up the stack
 2628 00000EE4 BE[6418]                                mov si,crlf_msg
 2629 00000EE7 E86E02                                  call cwritestr
 2630 00000EEA BE[4F18]                                mov si,loading_msg              ; Write new "Loading " for
 2631 00000EED E86802                                  call cwritestr                  ; the benefit of the kernel
 2632 00000EF0 07                                      pop es                          ; Restore original ES
 2633 00000EF1 C3                                      ret
 2634
 2635                                  ;
 2636                                  ; abort_check: let the user abort with <ESC> or <Ctrl-C>
 2637                                  ;
 2638                                  abort_check:
 2639 00000EF2 E87002                                  call pollchar
 2640 00000EF5 7423                                    jz ac_ret1
 2641 00000EF7 60                                      pusha
 2642 00000EF8 E88102                                  call getchar
 2643 00000EFB 3C1B                                    cmp al,27                       ; <ESC>
 2644 00000EFD 7404                                    je ac_kill
 2645 00000EFF 3C03                                    cmp al,3                        ; <Ctrl-C>
 2646 00000F01 7516                                    jne ac_ret2
 2647 00000F03 BE[5B18]                ac_kill:        mov si,aborted_msg
 2648
 2649                                  ;
 2650                                  ; abort_load: Called by various routines which wants to print a fatal
 2651                                  ;             error message and return to the command prompt.  Since this
 2652                                  ;             may happen at just about any stage of the boot process, assume
 2653                                  ;             our state is messed up, and just reset the segment registers
 2654                                  ;             and the stack forcibly.
 2655                                  ;
 2656                                  ;             SI    = offset (in _text) of error message to print
 2657                                  ;
 2658                                  abort_load:
 2659 00000F06 8CC8                                    mov ax,cs                       ; Restore CS = DS = ES
 2660 00000F08 8ED8                                    mov ds,ax
 2661 00000F0A 8EC0                                    mov es,ax
 2662 00000F0C FA                                      cli
 2663 00000F0D BCFA5F                                  mov sp,StackBuf-2*3             ; Reset stack
 2664 00000F10 8ED0                                    mov ss,ax                       ; Just in case...
 2665 00000F12 FB                                      sti
 2666 00000F13 E84202                                  call cwritestr                  ; Expects SI -> error msg
 2667 00000F16 E977F7                  al_ok:          jmp enter_command               ; Return to command prompt
 2668                                  ;
 2669                                  ; End of abort_check
 2670                                  ;
 2671 00000F19 61                      ac_ret2:        popa
 2672 00000F1A C3                      ac_ret1:        ret
 2673
 2674                                  ;
 2675                                  ; searchdir: Search the root directory for a pre-mangled filename in
 2676                                  ;            DS:DI.  This routine is similar to the one in the boot
 2677                                  ;            sector, but is a little less Draconian when it comes to
 2678                                  ;            error handling, plus it reads the root directory in
 2679                                  ;            larger chunks than a sector at a time (which is probably
 2680                                  ;            a waste of coding effort, but I like to do things right).
 2681                                  ;
 2682                                  ;            FIXME: usually we can load the entire root dir in memory,
 2683                                  ;            and files are usually at the beginning anyway.  It probably
 2684                                  ;            would be worthwhile to remember if we have the first chunk
 2685                                  ;            in memory and skip the load if that (it would speed up online
 2686                                  ;            help, mainly.)
 2687                                  ;
 2688                                  ;            NOTE: This file considers finding a zero-length file an
 2689                                  ;            error.  This is so we don't have to deal with that special
 2690                                  ;            case elsewhere in the program (most loops have the test
 2691                                  ;            at the end).
 2692                                  ;
 2693                                  ;            If successful:
 2694                                  ;               ZF clear
 2695                                  ;               SI      = cluster # for the first cluster
 2696                                  ;               DX:AX   = file length in bytes
 2697                                  ;            If unsuccessful
 2698                                  ;               ZF set
 2699                                  ;
 2700
 2701                                  searchdir:
 2702 00000F1B A1[1100]                                mov ax,[bsRootDirEnts]
 2703 00000F1E A3EA64                                  mov [DirScanCtr],ax
 2704 00000F21 A1E864                                  mov ax,[RootDirSize]
 2705 00000F24 A3EC64                                  mov [DirBlocksLeft],ax
 2706 00000F27 A1DC64                                  mov ax,[RootDir1]
 2707 00000F2A 8B16DE64                                mov dx,[RootDir2]
 2708                                  scan_group:
 2709 00000F2E 8B2EEC64                                mov bp,[DirBlocksLeft]
 2710 00000F32 21ED                                    and bp,bp
 2711 00000F34 7467                                    jz dir_return
 2712 00000F36 3B2EFA64                                cmp bp,[BufSafeSec]
 2713 00000F3A 7604                                    jna load_last
 2714 00000F3C 8B2EFA64                                mov bp,[BufSafeSec]
 2715                                  load_last:
 2716 00000F40 292EEC64                                sub [DirBlocksLeft],bp
 2717 00000F44 50                                      push ax
 2718 00000F45 52                                      push dx
 2719 00000F46 A1[0B00]                                mov ax,[bsBytesPerSec]
 2720 00000F49 F7E5                                    mul bp
 2721 00000F4B 05E10F                                  add ax,trackbuf-31
 2722 00000F4E A3EE64                                  mov [EndofDirSec],ax    ; End of loaded
 2723 00000F51 5A                                      pop dx
 2724 00000F52 58                                      pop ax
 2725 00000F53 55                                      push bp                 ; Save number of sectors
 2726 00000F54 50                                      push ax                 ; Save present location
 2727 00000F55 52                                      push dx
 2728 00000F56 57                                      push di                 ; Save name
 2729 00000F57 BB0010                                  mov bx,trackbuf
 2730 00000F5A E815F2                                  call getlinsec
 2731 00000F5D 5F                                      pop di
 2732 00000F5E 5A                                      pop dx
 2733 00000F5F 58                                      pop ax
 2734 00000F60 5D                                      pop bp
 2735 00000F61 BE0010                                  mov si,trackbuf
 2736 00000F64 803C00                  dir_test_name:  cmp byte [si],0         ; Directory high water mark
 2737 00000F67 7434                                    je dir_return           ; Failed
 2738 00000F69 F6440B18                                test byte [si+11],18h   ; Check it really is a file
 2739 00000F6D 750B                                    jnz dir_not_this
 2740 00000F6F 57                                      push di
 2741 00000F70 56                                      push si
 2742 00000F71 B90B00                                  mov cx,11               ; Filename = 11 bytes
 2743 00000F74 F3A6                                    repe cmpsb
 2744 00000F76 5E                                      pop si
 2745 00000F77 5F                                      pop di
 2746 00000F78 7416                                    je dir_success
 2747 00000F7A 83C620                  dir_not_this:   add si,byte 32
 2748 00000F7D FF0EEA64                                dec word [DirScanCtr]
 2749 00000F81 741A                                    jz dir_return           ; Out of it...
 2750 00000F83 3B36EE64                                cmp si,[EndofDirSec]
 2751 00000F87 72DB                                    jb dir_test_name
 2752 00000F89 01E8                                    add ax,bp               ; Increment linear sector number
 2753 00000F8B 83D200                                  adc dx,byte 0
 2754 00000F8E EB9E                                    jmp short scan_group
 2755                                  dir_success:
 2756 00000F90 8B441C                                  mov ax,[si+28]          ; Length of file
 2757 00000F93 8B541E                                  mov dx,[si+30]
 2758 00000F96 8B741A                                  mov si,[si+26]          ; Cluster pointer
 2759 00000F99 89C3                                    mov bx,ax
 2760 00000F9B 09D3                                    or bx,dx                ; Sets ZF iff DX:AX is zero
 2761                                  dir_return:
 2762 00000F9D C3                                      ret
 2763
 2764                                  ;
 2765                                  ; adjust_screen: Set the internal variables associated with the screen size.
 2766                                  ;               This is a subroutine in case we're loading a custom font.
 2767                                  ;
 2768                                  adjust_screen:
 2769 00000F9E A08404                                  mov al,[BIOS_vidrows]
 2770 00000FA1 20C0                                    and al,al
 2771 00000FA3 7502                                    jnz vidrows_is_ok
 2772 00000FA5 B018                                    mov al,24                       ; No vidrows in BIOS, assume 25
 2773                                                                                  ; (Remember: vidrows == rows-1)
 2774 00000FA7 A21F65                  vidrows_is_ok:  mov [VidRows],al
 2775 00000FAA B40F                                    mov ah,0fh
 2776 00000FAC CD10                                    int 10h                         ; Read video state
 2777 00000FAE 883E1B65                                mov [TextPage],bh
 2778 00000FB2 FECC                                    dec ah                          ; Store count-1 (same as rows)
 2779 00000FB4 88261E65                                mov [VidCols],ah
 2780 00000FB8 C3                      bf_ret:         ret
 2781
 2782                                  ;
 2783                                  ; loadfont:     Load a .psf font file and install it onto the VGA console
 2784                                  ;               (if we're not on a VGA screen then ignore.)  It is called with
 2785                                  ;               SI and DX:AX set by routine searchdir
 2786                                  ;
 2787                                  loadfont:
 2788 00000FB9 BB0010                                  mov bx,trackbuf                 ; The trackbuf is >= 16K; the part
 2789 00000FBC 8B0EF864                                mov cx,[BufSafe]                ; of a PSF file we care about is no
 2790 00000FC0 E863F3                                  call getfssec                   ; more than 8K+4 bytes
 2791
 2792 00000FC3 A10010                                  mov ax,[trackbuf]               ; Magic number
 2793 00000FC6 3D3604                                  cmp ax,0436h
 2794 00000FC9 75ED                                    jne bf_ret
 2795
 2796 00000FCB A00210                                  mov al,[trackbuf+2]             ; File mode
 2797 00000FCE 3C03                                    cmp al,3                        ; Font modes 0-3 supported
 2798 00000FD0 77E6                                    ja bf_ret
 2799
 2800 00000FD2 8A3E0310                                mov bh,byte [trackbuf+3]        ; Height of font
 2801 00000FD6 80FF02                                  cmp bh,2                        ; VGA minimum
 2802 00000FD9 72DD                                    jb bf_ret
 2803 00000FDB 80FF20                                  cmp bh,32                       ; VGA maximum
 2804 00000FDE 77D8                                    ja bf_ret
 2805
 2806 00000FE0 BD0410                                  mov bp,trackbuf+4               ; Address of font data
 2807 00000FE3 30DB                                    xor bl,bl
 2808 00000FE5 B90001                                  mov cx,256
 2809 00000FE8 31D2                                    xor dx,dx
 2810 00000FEA B81011                                  mov ax,1110h
 2811 00000FED CD10                                    int 10h                         ; Load into VGA RAM
 2812
 2813 00000FEF 30DB                                    xor bl,bl
 2814 00000FF1 B80311                                  mov ax,1103h                    ; Select page 0
 2815 00000FF4 CD10                                    int 10h
 2816
 2817 00000FF6 EBA6                                    jmp short adjust_screen
 2818
 2819                                  ;
 2820                                  ; loadkeys:     Load a LILO-style keymap; SI and DX:AX set by searchdir
 2821                                  ;
 2822                                  loadkeys:
 2823 00000FF8 21D2                                    and dx,dx                       ; Should be 256 bytes exactly
 2824 00000FFA 751A                                    jne loadkeys_ret
 2825 00000FFC 3D0001                                  cmp ax,256
 2826 00000FFF 7515                                    jne loadkeys_ret
 2827
 2828 00001001 BB0010                                  mov bx,trackbuf
 2829 00001004 B90100                                  mov cx,1                        ; 1 cluster should be >= 256 bytes
 2830 00001007 E81CF3                                  call getfssec
 2831
 2832 0000100A BE0010                                  mov si,trackbuf
 2833 0000100D BF0063                                  mov di,KbdMap
 2834 00001010 B94000                                  mov cx,256 >> 2
 2835 00001013 F366A5                                  rep movsd
 2836
 2837 00001016 C3                      loadkeys_ret:   ret
 2838
 2839                                  ;
 2840                                  ; get_msg_file: Load a text file and write its contents to the screen,
 2841                                  ;               interpreting color codes.  Is called with SI and DX:AX
 2842                                  ;               set by routine searchdir
 2843                                  ;
 2844                                  get_msg_file:
 2845 00001017 C7061265[6B10]                          mov word [NextCharJump],msg_putchar ; State machine for color
 2846 0000101D C6061A6507                              mov byte [TextAttribute],07h    ; Default grey on white
 2847 00001022 60                                      pusha
 2848 00001023 8A3E1B65                                mov bh,[TextPage]
 2849 00001027 B403                                    mov ah,03h                      ; Read cursor position
 2850 00001029 CD10                                    int 10h
 2851 0000102B 89161C65                                mov [CursorDX],dx
 2852 0000102F 61                                      popa
 2853 00001030 50                      get_msg_chunk:  push ax                         ; DX:AX = length of file
 2854 00001031 52                                      push dx
 2855 00001032 BB0010                                  mov bx,trackbuf
 2856 00001035 8B0EF864                                mov cx,[BufSafe]
 2857 00001039 E8EAF2                                  call getfssec
 2858 0000103C 5A                                      pop dx
 2859 0000103D 58                                      pop ax
 2860 0000103E 56                                      push si                         ; Save current cluster
 2861 0000103F BE0010                                  mov si,trackbuf
 2862 00001042 8B0EFC64                                mov cx,[BufSafeBytes]           ; No more than many bytes
 2863 00001046 51                      print_msg_file: push cx
 2864 00001047 50                                      push ax
 2865 00001048 52                                      push dx
 2866 00001049 AC                                      lodsb
 2867 0000104A 3C1A                                    cmp al,1Ah                      ; ASCII EOF?
 2868 0000104C 7418                                    je msg_done_pop
 2869 0000104E FF161265                                call [NextCharJump]             ; Do what shall be done
 2870 00001052 5A                                      pop dx
 2871 00001053 58                                      pop ax
 2872 00001054 59                                      pop cx
 2873 00001055 83E801                                  sub ax,byte 1
 2874 00001058 83DA00                                  sbb dx,byte 0
 2875 0000105B 89C3                                    mov bx,ax
 2876 0000105D 09D3                                    or bx,dx
 2877 0000105F 7408                                    jz msg_done
 2878 00001061 E2E3                                    loop print_msg_file
 2879 00001063 5E                                      pop si
 2880 00001064 EBCA                                    jmp short get_msg_chunk
 2881                                  msg_done_pop:
 2882 00001066 83C406                                  add sp,byte 6                   ; Lose 3 words on the stack
 2883                                  msg_done:
 2884 00001069 5E                                      pop si
 2885 0000106A C3                                      ret
 2886                                  msg_putchar:                                    ; Normal character
 2887 0000106B 3C0F                                    cmp al,0Fh                      ; ^O = color code follows
 2888 0000106D 7434                                    je msg_ctrl_o
 2889 0000106F 3C0D                                    cmp al,0Dh                      ; Ignore <CR>
 2890 00001071 742F                                    je msg_ignore
 2891 00001073 3C0A                                    cmp al,0Ah                      ; <LF> = newline
 2892 00001075 7433                                    je msg_newline
 2893 00001077 3C0C                                    cmp al,0Ch                      ; <FF> = clear screen
 2894 00001079 7460                                    je msg_formfeed
 2895
 2896 0000107B E8A800                  msg_normal:     call write_serial               ; Write to serial port
 2897 0000107E 8B1E1A65                                mov bx,[TextAttrBX]
 2898 00001082 B409                                    mov ah,09h                      ; Write character/attribute
 2899 00001084 B90100                                  mov cx,1                        ; One character only
 2900 00001087 CD10                                    int 10h                         ; Write to screen
 2901 00001089 A01C65                                  mov al,[CursorCol]
 2902 0000108C 40                                      inc ax
 2903 0000108D 3A061E65                                cmp al,[VidCols]
 2904 00001091 7717                                    ja msg_newline
 2905 00001093 A21C65                                  mov [CursorCol],al
 2906
 2907 00001096 8A3E1B65                msg_gotoxy:     mov bh,[TextPage]
 2908 0000109A 8B161C65                                mov dx,[CursorDX]
 2909 0000109E B402                                    mov ah,02h                      ; Set cursor position
 2910 000010A0 CD10                                    int 10h
 2911 000010A2 C3                      msg_ignore:     ret
 2912                                  msg_ctrl_o:                                     ; ^O = color code follows
 2913 000010A3 C7061265[F810]                          mov word [NextCharJump],msg_setbg
 2914 000010A9 C3                                      ret
 2915                                  msg_newline:                                    ; Newline char or end of line
 2916 000010AA 56                                      push si
 2917 000010AB BE[6418]                                mov si,crlf_msg
 2918 000010AE E88F00                                  call write_serial_str
 2919 000010B1 5E                                      pop si
 2920 000010B2 C6061C6500                              mov byte [CursorCol],0
 2921 000010B7 A01D65                                  mov al,[CursorRow]
 2922 000010BA 40                                      inc ax
 2923 000010BB 3A061F65                                cmp al,[VidRows]
 2924 000010BF 7705                                    ja msg_scroll
 2925 000010C1 A21D65                                  mov [CursorRow],al
 2926 000010C4 EBD0                                    jmp short msg_gotoxy
 2927 000010C6 31C9                    msg_scroll:     xor cx,cx                       ; Upper left hand corner
 2928 000010C8 8B161E65                                mov dx,[ScreenSize]
 2929 000010CC 88361D65                                mov [CursorRow],dh              ; New cursor at the bottom
 2930 000010D0 8A3E1A65                                mov bh,[TextAttribute]
 2931 000010D4 B80106                                  mov ax,0601h                    ; Scroll up one line
 2932 000010D7 CD10                                    int 10h
 2933 000010D9 EBBB                                    jmp short msg_gotoxy
 2934                                  msg_formfeed:                                   ; Form feed character
 2935 000010DB 56                                      push si
 2936 000010DC BE[6718]                                mov si,crff_msg
 2937 000010DF E85E00                                  call write_serial_str
 2938 000010E2 5E                                      pop si
 2939 000010E3 31C9                                    xor cx,cx
 2940 000010E5 890E1C65                                mov [CursorDX],cx               ; Upper lefthand corner
 2941 000010E9 8B161E65                                mov dx,[ScreenSize]
 2942 000010ED 8A3E1A65                                mov bh,[TextAttribute]
 2943 000010F1 B80006                                  mov ax,0600h                    ; Clear screen region
 2944 000010F4 CD10                                    int 10h
 2945 000010F6 EB9E                                    jmp short msg_gotoxy
 2946                                  msg_setbg:                                      ; Color background character
 2947 000010F8 E84A02                                  call unhexchar
 2948 000010FB 721D                                    jc msg_color_bad
 2949 000010FD C0E004                                  shl al,4
 2950 00001100 A21A65                                  mov [TextAttribute],al
 2951 00001103 C7061265[0A11]                          mov word [NextCharJump],msg_setfg
 2952 00001109 C3                                      ret
 2953                                  msg_setfg:                                      ; Color foreground character
 2954 0000110A E83802                                  call unhexchar
 2955 0000110D 720B                                    jc msg_color_bad
 2956 0000110F 08061A65                                or [TextAttribute],al           ; setbg set foreground to 0
 2957 00001113 C7061265[6B10]                          mov word [NextCharJump],msg_putchar
 2958 00001119 C3                                      ret
 2959                                  msg_color_bad:
 2960 0000111A C6061A6507                              mov byte [TextAttribute],07h    ; Default attribute
 2961 0000111F C7061265[6B10]                          mov word [NextCharJump],msg_putchar
 2962 00001125 C3                                      ret
 2963
 2964                                  ;
 2965                                  ; write_serial: If serial output is enabled, write character on serial port
 2966                                  ;
 2967                                  write_serial:
 2968 00001126 60                                      pusha
 2969 00001127 8B1E[CC18]                              mov bx,[SerialPort]
 2970 0000112B 21DB                                    and bx,bx
 2971 0000112D 740F                                    je .noserial
 2972 0000112F 50                                      push ax
 2973 00001130 8D5705                  .waitspace:     lea dx,[bx+5]                   ; Wait for space in transmit reg
 2974 00001133 EC                                      in al,dx
 2975 00001134 A820                                    test al,20h
 2976 00001136 74F8                                    jz .waitspace
 2977 00001138 87D3                                    xchg dx,bx
 2978 0000113A 58                                      pop ax
 2979 0000113B E89BFC                                  call slow_out                   ; Send data
 2980 0000113E 61                      .noserial:      popa
 2981 0000113F C3                                      ret
 2982
 2983                                  ;
 2984                                  ; write_serial_str: write_serial for strings
 2985                                  ;
 2986                                  write_serial_str:
 2987 00001140 AC                      .loop           lodsb
 2988 00001141 20C0                                    and al,al
 2989 00001143 7405                                    jz .end
 2990 00001145 E8DEFF                                  call write_serial
 2991 00001148 EBF6                                    jmp short .loop
 2992 0000114A C3                      .end:           ret
 2993
 2994                                  ;
 2995                                  ; writechr:     Write a single character in AL to the console without
 2996                                  ;               mangling any registers
 2997                                  ;
 2998                                  writechr:
 2999 0000114B E8D8FF                                  call write_serial       ; write to serial port if needed
 3000 0000114E 60                                      pusha
 3001 0000114F B40E                                    mov ah,0Eh
 3002 00001151 BB0700                                  mov bx,0007h            ; white text on this page
 3003 00001154 CD10                                    int 10h
 3004 00001156 61                                      popa
 3005 00001157 C3                                      ret
 3006
 3007                                  ;
 3008                                  ; cwritestr: write a null-terminated string to the console, saving
 3009                                  ;            registers on entry.
 3010                                  ;
 3011                                  cwritestr:
 3012 00001158 60                                      pusha
 3013 00001159 AC                      .top:           lodsb
 3014 0000115A 20C0                                    and al,al
 3015 0000115C 7405                                    jz .end
 3016 0000115E E8EAFF                                  call writechr
 3017 00001161 EBF6                                    jmp short .top
 3018 00001163 61                      .end:           popa
 3019 00001164 C3                                      ret
 3020
 3021                                  ;
 3022                                  ; pollchar: check if we have an input character pending (ZF = 0)
 3023                                  ;
 3024                                  pollchar:
 3025 00001165 60                                      pusha
 3026 00001166 B401                                    mov ah,1                ; Poll keyboard
 3027 00001168 CD16                                    int 16h
 3028 0000116A 750E                                    jnz .done               ; Keyboard response
 3029 0000116C 8B16[CC18]                              mov dx,[SerialPort]
 3030 00001170 21D2                                    and dx,dx
 3031 00001172 7406                                    jz .done                ; No serial port -> no input
 3032 00001174 83C205                                  add dx,byte 5           ; Serial status register
 3033 00001177 EC                                      in al,dx
 3034 00001178 A801                                    test al,1               ; ZF = 0 if traffic
 3035 0000117A 61                      .done:          popa
 3036 0000117B C3                                      ret
 3037
 3038                                  ;
 3039                                  ; getchar: Read a character from keyboard or serial port
 3040                                  ;
 3041                                  getchar:
 3042 0000117C B401                    .again:         mov ah,1                ; Poll keyboard
 3043 0000117E CD16                                    int 16h
 3044 00001180 7516                                    jnz .kbd                ; Keyboard input?
 3045 00001182 8B1E[CC18]                              mov bx,[SerialPort]
 3046 00001186 21DB                                    and bx,bx
 3047 00001188 74F2                                    jz .again
 3048 0000118A 8D5705                                  lea dx,[bx+5]           ; Serial status register
 3049 0000118D EC                                      in al,dx
 3050 0000118E A801                                    test al,1
 3051 00001190 74EA                                    jz .again
 3052 00001192 30E4                    .serial:        xor ah,ah               ; Avoid confusion
 3053 00001194 87D3                                    xchg dx,bx              ; Data port
 3054 00001196 EC                                      in al,dx
 3055 00001197 C3                                      ret
 3056 00001198 31C0                    .kbd:           xor ax,ax               ; Get keyboard input
 3057 0000119A CD16                                    int 16h
 3058 0000119C 20C0                                    and al,al
 3059 0000119E 7404                                    jz .func_key
 3060 000011A0 BB0063                                  mov bx,KbdMap           ; Convert character sets
 3061 000011A3 D7                                      xlatb
 3062 000011A4 C3                      .func_key:      ret
 3063
 3064                                  ;
 3065                                  ;
 3066                                  ; kaboom2: once everything is loaded, replace the part of kaboom
 3067                                  ;          starting with "kaboom.patch" with this part
 3068
 3069                                  kaboom2:
 3070 000011A5 BE[0D18]                                mov si,err_bootfailed
 3071 000011A8 E8ADFF                                  call cwritestr
 3072 000011AB E8CEFF                                  call getchar
 3073 000011AE CD19                                    int 19h                 ; And try once more to boot...
 3074 000011B0 EBFE                    .norge:         jmp short .norge        ; If int 19h returned; this is the end
 3075
 3076                                  ;
 3077                                  ; open,getc:    Load a file a character at a time for parsing in a manner
 3078                                  ;               similar to the C library getc routine.  Only one simultaneous
 3079                                  ;               use is supported.  Note: "open" trashes the trackbuf.
 3080                                  ;
 3081                                  ;               open:   Input:  mangled filename in DS:DI
 3082                                  ;                       Output: ZF set on file not found or zero length
 3083                                  ;
 3084                                  ;               getc:   Output: CF set on end of file
 3085                                  ;                               Character loaded in AL
 3086                                  ;
 3087                                  open:
 3088 000011B2 E866FD                                  call searchdir
 3089 000011B5 7427                                    jz open_return
 3090 000011B7 9C                                      pushf
 3091 000011B8 A3E464                                  mov [FBytes1],ax
 3092 000011BB 8916E664                                mov [FBytes2],dx
 3093 000011BF 0306F264                                add ax,[ClustSize]
 3094 000011C3 83D200                                  adc dx,byte 0
 3095 000011C6 83E801                                  sub ax,byte 1
 3096 000011C9 83DA00                                  sbb dx,byte 0
 3097 000011CC F736F264                                div word [ClustSize]
 3098 000011D0 A30665                                  mov [FClust],ax         ; Number of clusters
 3099 000011D3 89360865                                mov [FNextClust],si     ; Cluster pointer
 3100 000011D7 A1FE64                                  mov ax,[EndOfGetCBuf]   ; Pointer at end of buffer ->
 3101 000011DA A30A65                                  mov [FPtr],ax           ;  nothing loaded yet
 3102 000011DD 9D                                      popf                    ; Restore no ZF
 3103 000011DE C3                      open_return:    ret
 3104
 3105                                  ;
 3106                                  getc:
 3107 000011DF F9                                      stc                     ; If we exit here -> EOF
 3108 000011E0 668B0EE464                              mov ecx,[FBytes]
 3109 000011E5 66E33B                                  jecxz getc_ret
 3110 000011E8 8B360A65                                mov si,[FPtr]
 3111 000011EC 3B36FE64                                cmp si,[EndOfGetCBuf]
 3112 000011F0 7226                                    jb getc_loaded
 3113                                                  ; Buffer empty -- load another set
 3114 000011F2 8B0E0665                                mov cx,[FClust]
 3115 000011F6 3B0EF864                                cmp cx,[BufSafe]
 3116 000011FA 7604                                    jna getc_oksize
 3117 000011FC 8B0EF864                                mov cx,[BufSafe]
 3118 00001200 290E0665                getc_oksize:    sub [FClust],cx         ; Reduce remaining clusters
 3119 00001204 8B360865                                mov si,[FNextClust]
 3120 00001208 BB0098                                  mov bx,getcbuf
 3121 0000120B 53                                      push bx
 3122 0000120C 06                                      push es                 ; ES may be != DS, save old ES
 3123 0000120D 1E                                      push ds                 ; Trackbuf is in DS, not ES
 3124 0000120E 07                                      pop es
 3125 0000120F E814F1                                  call getfssec           ; Load a trackbuf full of data
 3126 00001212 89360865                                mov [FNextClust],si     ; Store new next pointer
 3127 00001216 07                                      pop es                  ; Restore ES
 3128 00001217 5E                                      pop si                  ; SI -> newly loaded data
 3129 00001218 AC                      getc_loaded:    lodsb                   ; Load a byte
 3130 00001219 89360A65                                mov [FPtr],si           ; Update next byte pointer
 3131 0000121D 66FF0EE464                              dec dword [FBytes]      ; Update bytes left counter (CF = 1)
 3132 00001222 F8                                      clc                     ; Not EOF
 3133 00001223 C3                      getc_ret:       ret
 3134
 3135                                  ;
 3136                                  ; ungetc:       Push a character (in AL) back into the getc buffer
 3137                                  ;               Note: if more than one byte is pushed back, this may cause
 3138                                  ;               bytes to be written below the getc buffer boundary.  If there
 3139                                  ;               is a risk for this to occur, the getcbuf base address should
 3140                                  ;               be moved up.
 3141                                  ;
 3142                                  ungetc:
 3143 00001224 8B360A65                                mov si,[FPtr]
 3144 00001228 4E                                      dec si
 3145 00001229 8804                                    mov [si],al
 3146 0000122B 89360A65                                mov [FPtr],si
 3147 0000122F 66FF06E464                              inc dword [FBytes]
 3148 00001234 C3                                      ret
 3149
 3150                                  ;
 3151                                  ; skipspace:    Skip leading whitespace using "getc".  If we hit end-of-line
 3152                                  ;               or end-of-file, return with carry set; ZF = true of EOF
 3153                                  ;               ZF = false for EOLN; otherwise CF = ZF = 0.
 3154                                  ;
 3155                                  ;               Otherwise AL = first character after whitespace
 3156                                  ;
 3157                                  skipspace:
 3158 00001235 E8A7FF                  skipspace_loop: call getc
 3159 00001238 720D                                    jc skipspace_eof
 3160 0000123A 3C1A                                    cmp al,1Ah                      ; DOS EOF
 3161 0000123C 7409                                    je skipspace_eof
 3162 0000123E 3C0A                                    cmp al,0Ah
 3163 00001240 7409                                    je skipspace_eoln
 3164 00001242 3C20                                    cmp al,' '
 3165 00001244 76EF                                    jbe skipspace_loop
 3166 00001246 C3                                      ret                             ; CF = ZF = 0
 3167 00001247 38C0                    skipspace_eof:  cmp al,al                       ; Set ZF
 3168 00001249 F9                                      stc                             ; Set CF
 3169 0000124A C3                                      ret
 3170 0000124B 04FF                    skipspace_eoln: add al,0FFh                     ; Set CF, clear ZF
 3171 0000124D C3                                      ret
 3172
 3173                                  ;
 3174                                  ; getkeyword:   Get a keyword from the current "getc" file; only the two
 3175                                  ;               first characters are considered significant.
 3176                                  ;
 3177                                  ;               Lines beginning with ASCII characters 33-47 are treated
 3178                                  ;               as comments and ignored; other lines are checked for
 3179                                  ;               validity by scanning through the keywd_table.
 3180                                  ;
 3181                                  ;               The keyword and subsequent whitespace is skipped.
 3182                                  ;
 3183                                  ;               On EOF, CF = 1; otherwise, CF = 0, AL:AH = lowercase char pair
 3184                                  ;
 3185                                  getkeyword:
 3186 0000124E E8E4FF                  gkw_find:       call skipspace
 3187 00001251 7438                                    jz gkw_eof              ; end of file
 3188 00001253 72F9                                    jc gkw_find             ; end of line: try again
 3189 00001255 3C30                                    cmp al,'0'
 3190 00001257 7246                                    jb gkw_skipline         ; skip comment line
 3191 00001259 50                                      push ax
 3192 0000125A E882FF                                  call getc
 3193 0000125D 5B                                      pop bx
 3194 0000125E 722B                                    jc gkw_eof
 3195 00001260 88C7                                    mov bh,al               ; Move character pair into BL:BH
 3196 00001262 81CB2020                                or bx,2020h             ; Lower-case it
 3197 00001266 BE[7C18]                                mov si,keywd_table
 3198 00001269 AD                      gkw_check:      lodsw
 3199 0000126A 21C0                                    and ax,ax
 3200 0000126C 7429                                    jz gkw_badline          ; Bad keyword, write message
 3201 0000126E 39D8                                    cmp ax,bx
 3202 00001270 75F7                                    jne gkw_check
 3203 00001272 50                                      push ax
 3204                                  gkw_skiprest:
 3205 00001273 E869FF                                  call getc
 3206 00001276 7212                                    jc gkw_eof_pop
 3207 00001278 3C30                                    cmp al,'0'
 3208 0000127A 77F7                                    ja gkw_skiprest
 3209 0000127C E8A5FF                                  call ungetc
 3210 0000127F E8B3FF                                  call skipspace
 3211 00001282 7406                                    jz gkw_eof_pop
 3212 00001284 7206                                    jc gkw_missingpar       ; Missing parameter after keyword
 3213 00001286 E89BFF                                  call ungetc             ; Return character to buffer
 3214 00001289 F8                                      clc                     ; Successful return
 3215 0000128A 58                      gkw_eof_pop:    pop ax
 3216 0000128B C3                      gkw_eof:        ret                     ; CF = 1 on all EOF conditions
 3217 0000128C 58                      gkw_missingpar: pop ax
 3218 0000128D BE[CC16]                                mov si,err_noparm
 3219 00001290 E8C5FE                                  call cwritestr
 3220 00001293 E9B8FF                                  jmp gkw_find
 3221 00001296 58                      gkw_badline_pop: pop ax
 3222 00001297 BE[A916]                gkw_badline:    mov si,err_badcfg
 3223 0000129A E8BBFE                                  call cwritestr
 3224 0000129D EBAF                                    jmp short gkw_find
 3225 0000129F 3C0A                    gkw_skipline:   cmp al,10               ; Scan for LF
 3226 000012A1 74AB                                    je gkw_find
 3227 000012A3 E839FF                                  call getc
 3228 000012A6 72E3                                    jc gkw_eof
 3229 000012A8 EBF5                                    jmp short gkw_skipline
 3230
 3231                                  ;
 3232                                  ; getint:       Load an integer from the getc file.
 3233                                  ;               Return CF if error; otherwise return integer in EBX
 3234                                  ;
 3235                                  getint:
 3236 000012AA BFA064                                  mov di,NumBuf
 3237 000012AD 81FFAF64                gi_getnum:      cmp di,NumBufEnd        ; Last byte in NumBuf
 3238 000012B1 730F                                    jae gi_loaded
 3239 000012B3 57                                      push di
 3240 000012B4 E828FF                                  call getc
 3241 000012B7 5F                                      pop di
 3242 000012B8 7208                                    jc gi_loaded
 3243 000012BA AA                                      stosb
 3244 000012BB 3C2D                                    cmp al,'-'
 3245 000012BD 73EE                                    jnb gi_getnum
 3246 000012BF E862FF                                  call ungetc             ; Unget non-numeric
 3247 000012C2 C60500                  gi_loaded:      mov byte [di],0
 3248 000012C5 BEA064                                  mov si,NumBuf
 3249                                                  ; Fall through to parseint
 3250
 3251                                  ;
 3252                                  ; parseint:     Convert an integer to a number in EBX
 3253                                  ;               Get characters from string in DS:SI
 3254                                  ;               Return CF on error
 3255                                  ;               DS:SI points to first character after number
 3256                                  ;
 3257                                  ;               Syntaxes accepted: [-]dec, [-]0+oct, [-]0x+hex, val+K, val+M
 3258                                  ;
 3259                                  parseint:
 3260 000012C8 6650                                    push eax
 3261 000012CA 6651                                    push ecx
 3262 000012CC 55                                      push bp
 3263 000012CD 6631C0                                  xor eax,eax             ; Current digit (keep eax == al)
 3264 000012D0 6689C3                                  mov ebx,eax             ; Accumulator
 3265 000012D3 6689D9                                  mov ecx,ebx             ; Base
 3266 000012D6 31ED                                    xor bp,bp               ; Used for negative flag
 3267 000012D8 AC                      pi_begin:       lodsb
 3268 000012D9 3C2D                                    cmp al,'-'
 3269 000012DB 7506                                    jne pi_not_minus
 3270 000012DD 81F50100                                xor bp,1                ; Set unary minus flag
 3271 000012E1 EBF5                                    jmp short pi_begin
 3272                                  pi_not_minus:
 3273 000012E3 3C30                                    cmp al,'0'
 3274 000012E5 724F                                    jb pi_err
 3275 000012E7 7408                                    je pi_octhex
 3276 000012E9 3C39                                    cmp al,'9'
 3277 000012EB 7749                                    ja pi_err
 3278 000012ED B10A                                    mov cl,10               ; Base = decimal
 3279 000012EF EB17                                    jmp short pi_foundbase
 3280                                  pi_octhex:
 3281 000012F1 AC                                      lodsb
 3282 000012F2 3C30                                    cmp al,'0'
 3283 000012F4 7225                                    jb pi_km                ; Value is zero
 3284 000012F6 0C20                                    or al,20h               ; Downcase
 3285 000012F8 3C78                                    cmp al,'x'
 3286 000012FA 7408                                    je pi_ishex
 3287 000012FC 3C37                                    cmp al,'7'
 3288 000012FE 7736                                    ja pi_err
 3289 00001300 B108                                    mov cl,8                ; Base = octal
 3290 00001302 EB04                                    jmp short pi_foundbase
 3291                                  pi_ishex:
 3292 00001304 B030                                    mov al,'0'              ; No numeric value accrued yet
 3293 00001306 B110                                    mov cl,16               ; Base = hex
 3294                                  pi_foundbase:
 3295 00001308 E83A00                                  call unhexchar
 3296 0000130B 720E                                    jc pi_km                ; Not a (hex) digit
 3297 0000130D 38C8                                    cmp al,cl
 3298 0000130F 730A                                    jae pi_km               ; Invalid for base
 3299 00001311 660FAFD9                                imul ebx,ecx            ; Multiply accumulated by base
 3300 00001315 6601C3                                  add ebx,eax             ; Add current digit
 3301 00001318 AC                                      lodsb
 3302 00001319 EBED                                    jmp short pi_foundbase
 3303                                  pi_km:
 3304 0000131B 4E                                      dec si                  ; Back up to last non-numeric
 3305 0000131C AC                                      lodsb
 3306 0000131D 0C20                                    or al,20h
 3307 0000131F 3C6B                                    cmp al,'k'
 3308 00001321 7416                                    je pi_isk
 3309 00001323 3C6D                                    cmp al,'m'
 3310 00001325 7418                                    je pi_ism
 3311 00001327 4E                                      dec si                  ; Back up
 3312 00001328 21ED                    pi_fini:        and bp,bp
 3313 0000132A 7404                                    jz pi_ret               ; CF=0!
 3314 0000132C 66F7DB                                  neg ebx                 ; Value was negative
 3315 0000132F F8                      pi_done:        clc
 3316 00001330 5D                      pi_ret:         pop bp
 3317 00001331 6659                                    pop ecx
 3318 00001333 6658                                    pop eax
 3319 00001335 C3                                      ret
 3320 00001336 F9                      pi_err:         stc
 3321 00001337 EBF7                                    jmp short pi_ret
 3322 00001339 66C1E30A                pi_isk:         shl ebx,10              ; x 2^10
 3323 0000133D EBF0                                    jmp short pi_done
 3324 0000133F 66C1E314                pi_ism:         shl ebx,20              ; x 2^20
 3325 00001343 EBEA                                    jmp short pi_done
 3326
 3327                                  ;
 3328                                  ; unhexchar:    Convert a hexadecimal digit in AL to the equivalent number;
 3329                                  ;               return CF=1 if not a hex digit
 3330                                  ;
 3331                                  unhexchar:
 3332 00001345 3C30                                    cmp al,'0'
 3333 00001347 7215                                    jb uxc_ret              ; If failure, CF == 1 already
 3334 00001349 3C39                                    cmp al,'9'
 3335 0000134B 7703                                    ja uxc_1
 3336 0000134D 2C30                                    sub al,'0'              ; CF <- 0
 3337 0000134F C3                                      ret
 3338 00001350 0C20                    uxc_1:          or al,20h               ; upper case -> lower case
 3339 00001352 3C61                                    cmp al,'a'
 3340 00001354 7208                                    jb uxc_ret              ; If failure, CF == 1 already
 3341 00001356 3C66                                    cmp al,'f'
 3342 00001358 7703                                    ja uxc_err
 3343 0000135A 2C57                                    sub al,'a'-10           ; CF <- 0
 3344 0000135C C3                                      ret
 3345 0000135D F9                      uxc_err:        stc
 3346 0000135E C3                      uxc_ret:        ret
 3347
 3348                                  ;
 3349                                  ;
 3350                                  ; getline:      Get a command line, converting control characters to spaces
 3351                                  ;               and collapsing streches to one; a space is appended to the
 3352                                  ;               end of the string, unless the line is empty.
 3353                                  ;               The line is terminated by ^J, ^Z or EOF and is written
 3354                                  ;               to ES:DI.  On return, DI points to first char after string.
 3355                                  ;               CF is set if we hit EOF.
 3356                                  ;
 3357                                  getline:
 3358 0000135F E8D3FE                                  call skipspace
 3359 00001362 B201                                    mov dl,1                ; Empty line -> empty string.
 3360 00001364 742B                                    jz gl_eof               ; eof
 3361 00001366 7226                                    jc gl_eoln              ; eoln
 3362 00001368 E8B9FE                                  call ungetc
 3363 0000136B 52                      gl_fillloop:    push dx
 3364 0000136C 57                                      push di
 3365 0000136D E86FFE                                  call getc
 3366 00001370 5F                                      pop di
 3367 00001371 5A                                      pop dx
 3368 00001372 721E                                    jc gl_ret               ; CF set!
 3369 00001374 3C20                                    cmp al,' '
 3370 00001376 7605                                    jna gl_ctrl
 3371 00001378 31D2                                    xor dx,dx
 3372 0000137A AA                      gl_store:       stosb
 3373 0000137B EBEE                                    jmp short gl_fillloop
 3374 0000137D 3C0A                    gl_ctrl:        cmp al,10
 3375 0000137F 7411                                    je gl_ret               ; CF clear!
 3376 00001381 3C1A                                    cmp al,26
 3377 00001383 740C                                    je gl_eof
 3378 00001385 20D2                                    and dl,dl
 3379 00001387 75E2                                    jnz gl_fillloop         ; Ignore multiple spaces
 3380 00001389 B020                                    mov al,' '              ; Ctrl -> space
 3381 0000138B 42                                      inc dx
 3382 0000138C EBEC                                    jmp short gl_store
 3383 0000138E F8                      gl_eoln:        clc                     ; End of line is not end of file
 3384 0000138F EB01                                    jmp short gl_ret
 3385 00001391 F9                      gl_eof:         stc
 3386 00001392 9C                      gl_ret:         pushf                   ; We want the last char to be space!
 3387 00001393 20D2                                    and dl,dl
 3388 00001395 7503                                    jnz gl_xret
 3389 00001397 B020                                    mov al,' '
 3390 00001399 AA                                      stosb
 3391 0000139A 9D                      gl_xret:        popf
 3392 0000139B C3                                      ret
 3393
 3394
 3395                                  %ifdef debug            ; This code for debugging only
 3396                                  ;
 3397                                  ; dumpregs:     Dumps the contents of all registers
 3398                                  ;
 3399                                                  assume ds:_text, es:NOTHING, fs:NOTHING, gs:NOTHING
 3400                                  dumpregs        proc near               ; When calling, IP is on stack
 3401                                                  pushf                   ; Store flags
 3402                                                  pusha
 3403                                                  push ds
 3404                                                  push es
 3405                                                  push fs
 3406                                                  push gs
 3407                                                  push cs                 ; Set DS <- CS
 3408                                                  pop ds
 3409                                                  cld                     ; Clear direction flag
 3410                                                  mov si,offset crlf_msg
 3411                                                  call cwritestr
 3412                                                  mov bx,sp
 3413                                                  add bx,byte 26
 3414                                                  mov si,offset regnames
 3415                                                  mov cx,2                ; 2*7 registers to dump
 3416                                  dump_line:      push cx
 3417                                                  mov cx,7                ; 7 registers per line
 3418                                  dump_reg:       push cx
 3419                                                  mov cx,4                ; 4 characters/register name
 3420                                  wr_reg_name:    lodsb
 3421                                                  call writechr
 3422                                                  loop wr_reg_name
 3423                                                  mov ax,ss:[bx]
 3424                                                  dec bx
 3425                                                  dec bx
 3426                                                  call writehex
 3427                                                  pop cx
 3428                                                  loop dump_reg
 3429                                                  mov al,0Dh              ; <CR>
 3430                                                  call writechr
 3431                                                  mov al,0Ah              ; <LF>
 3432                                                  call writechr
 3433                                                  pop cx
 3434                                                  loop dump_line
 3435                                                  pop gs
 3436                                                  pop fs
 3437                                                  pop es
 3438                                                  pop ds
 3439                                                  popa                    ; Restore the remainder
 3440                                                  popf                    ; Restore flags
 3441                                                  ret
 3442                                  dumpregs        endp
 3443
 3444                                  regnames        db ' IP: FL: AX: CX: DX: BX: SP: BP: SI: DI: DS: ES: FS: GS:'
 3445
 3446                                  ;
 3447                                  ; writehex:     Writes a 16-bit hexadecimal number (in AX)
 3448                                  ;
 3449                                  writehex        proc near
 3450                                                  push bx
 3451                                                  push cx
 3452                                                  mov cx,4                ; 4 numbers
 3453                                  write_hexdig:   xor bx,bx
 3454                                                  push cx
 3455                                                  mov cx,4                ; 4 bits/digit
 3456                                  xfer_digit:     shl ax,1
 3457                                                  rcl bx,1
 3458                                                  loop xfer_digit
 3459                                                  push ax
 3460                                                  mov ax,bx
 3461                                                  or al,'0'
 3462                                                  cmp al,'9'
 3463                                                  jna ok_digit
 3464                                                  add al,'A'-'0'-10
 3465                                  ok_digit:       call writechr
 3466                                                  pop ax
 3467                                                  pop cx
 3468                                                  loop write_hexdig
 3469                                                  pop cx
 3470                                                  pop bx
 3471                                                  ret
 3472                                  writehex        endp
 3473
 3474                                  debug_magic     dw 0D00Dh
 3475
 3476                                  %endif ; debug
 3477                                  ;
 3478                                  ; mangle_name: Mangle a DOS filename pointed to by DS:SI into a buffer pointed
 3479                                  ;              to by ES:DI; ends on encountering any whitespace
 3480                                  ;
 3481
 3482                                  mangle_name:
 3483 0000139C B90B00                                  mov cx,11                       ; # of bytes to write
 3484                                  mn_loop:
 3485 0000139F AC                                      lodsb
 3486 000013A0 3C20                                    cmp al,' '                      ; If control or space, end
 3487 000013A2 762B                                    jna mn_end
 3488 000013A4 3C2E                                    cmp al,'.'                      ; Period -> space-fill
 3489 000013A6 740C                                    je mn_is_period
 3490 000013A8 3C61                                    cmp al,'a'
 3491 000013AA 7220                                    jb mn_not_lower
 3492 000013AC 3C7A                                    cmp al,'z'
 3493 000013AE 770F                                    ja mn_not_uslower
 3494 000013B0 2C20                                    sub al,020h
 3495 000013B2 EB18                                    jmp short mn_not_lower
 3496 000013B4 B020                    mn_is_period:   mov al,' '                      ; We need to space-fill
 3497 000013B6 81F90300                mn_period_loop: cmp cx,3                        ; If <= 3 characters left
 3498 000013BA 76E3                                    jbe mn_loop                     ; Just ignore it
 3499 000013BC AA                                      stosb                           ; Otherwise, write a period
 3500 000013BD E2F7                                    loop mn_period_loop             ; Dec CX and (always) jump
 3501 000013BF 3C81                    mn_not_uslower: cmp al,ucase_low
 3502 000013C1 7209                                    jb mn_not_lower
 3503 000013C3 3CA4                                    cmp al,ucase_high
 3504 000013C5 7705                                    ja mn_not_lower
 3505 000013C7 BB[5313]                                mov bx,ucase_tab-ucase_low
 3506 000013CA 2ED7                                    cs xlatb
 3507 000013CC AA                      mn_not_lower:   stosb
 3508 000013CD E2D0                                    loop mn_loop                    ; Don't continue if too long
 3509                                  mn_end:
 3510 000013CF B020                                    mov al,' '                      ; Space-fill name
 3511 000013D1 F3AA                                    rep stosb                       ; Doesn't do anything if CX=0
 3512 000013D3 C3                                      ret                             ; Done
 3513
 3514                                  ;
 3515                                  ; Upper-case table for extended characters; this is technically code page 865,
 3516                                  ; but code page 437 users will probably not miss not being able to use the
 3517                                  ; cent sign in kernel images too much :-)
 3518                                  ;
 3519                                  ; The table only covers the range 129 to 164; the rest we can deal with.
 3520                                  ;
 3521                                  ucase_low       equ 129
 3522                                  ucase_high      equ 164
 3523 000013D4 9A90418E418F804545-     ucase_tab       db 154, 144, 'A', 142, 'A', 143, 128, 'EEEIII'
 3524 000013DD 45494949
 3525 000013E1 8E8F9092924F994F55-                     db 142, 143, 144, 146, 146, 'O', 153, 'OUUY', 153, 154
 3526 000013EA 5559999A
 3527 000013EE 9D9C9D9E9F41494F55-                     db 157, 156, 157, 158, 159, 'AIOU', 165
 3528 000013F7 A5
 3529
 3530                                  ;
 3531                                  ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
 3532                                  ;                filename to the conventional representation.  This is needed
 3533                                  ;                for the BOOT_IMAGE= parameter for the kernel.
 3534                                  ;                NOTE: A 13-byte buffer is mandatory, even if the string is
 3535                                  ;                known to be shorter.
 3536                                  ;
 3537                                  ;                DS:SI -> input mangled file name
 3538                                  ;                ES:DI -> output buffer
 3539                                  ;
 3540                                  ;                On return, DI points to the first byte after the output name,
 3541                                  ;                which is set to a null byte.
 3542                                  ;
 3543                                  unmangle_name:
 3544 000013F8 56                                      push si                 ; Save pointer to original name
 3545 000013F9 B90800                                  mov cx,8
 3546 000013FC 89FD                                    mov bp,di
 3547 000013FE AC                      un_copy_body:   lodsb
 3548 000013FF E82600                                  call lower_case
 3549 00001402 AA                                      stosb
 3550 00001403 3C20                                    cmp al,' '
 3551 00001405 7602                                    jbe un_cb_space
 3552 00001407 89FD                                    mov bp,di               ; Position of last nonblank+1
 3553 00001409 E2F3                    un_cb_space:    loop un_copy_body
 3554 0000140B 89EF                                    mov di,bp
 3555 0000140D B02E                                    mov al,'.'              ; Don't save
 3556 0000140F AA                                      stosb
 3557 00001410 B90300                                  mov cx,3
 3558 00001413 AC                      un_copy_ext:    lodsb
 3559 00001414 E81100                                  call lower_case
 3560 00001417 AA                                      stosb
 3561 00001418 3C20                                    cmp al,' '
 3562 0000141A 7602                                    jbe un_ce_space
 3563 0000141C 89FD                                    mov bp,di
 3564 0000141E E2F3                    un_ce_space:    loop un_copy_ext
 3565 00001420 89EF                                    mov di,bp
 3566 00001422 26C60500                                mov byte [es:di], 0
 3567 00001426 5E                                      pop si
 3568 00001427 C3                                      ret
 3569
 3570                                  ;
 3571                                  ; lower_case: Lower case a character in AL
 3572                                  ;
 3573                                  lower_case:
 3574 00001428 3C41                                    cmp al,'A'
 3575 0000142A 7216                                    jb lc_ret
 3576 0000142C 3C5A                                    cmp al,'Z'
 3577 0000142E 7703                                    ja lc_1
 3578 00001430 0C20                                    or al,20h
 3579 00001432 C3                                      ret
 3580 00001433 3C80                    lc_1:           cmp al,lcase_low
 3581 00001435 720B                                    jb lc_ret
 3582 00001437 3CA5                                    cmp al,lcase_high
 3583 00001439 7707                                    ja lc_ret
 3584 0000143B 53                                      push bx
 3585 0000143C BB[C313]                                mov bx,lcase_tab-lcase_low
 3586 0000143F 2ED7                                    cs xlatb
 3587 00001441 5B                                      pop bx
 3588 00001442 C3                      lc_ret:         ret
 3589
 3590                                  ;
 3591                                  ; Lower-case table for codepage 865
 3592                                  ;
 3593                                  lcase_low       equ 128
 3594                                  lcase_high      equ 165
 3595 00001443 878182838485868788-     lcase_tab       db 135, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138
 3596 0000144C 898A
 3597 0000144E 8B8C8D848682919193-                     db 139, 140, 141, 132, 134, 130, 145, 145, 147, 148, 149
 3598 00001457 9495
 3599 00001459 96979894819B9C9B9E-                     db 150, 151, 152, 148, 129, 155, 156, 155, 158, 159, 160
 3600 00001462 9FA0
 3601 00001464 A1A2A3A4A4                              db 161, 162, 163, 164, 164
 3602                                  ;
 3603                                  ; Various initialized or semi-initialized variables
 3604                                  ;
 3605 00001469 20436F707972696768-     copyright_str   db ' Copyright (C) 1994-', year, ' H. Peter Anvin'
 3606 00001472 742028432920313939-
 3607 0000147B 342D3139393920482E-
 3608 00001484 20506574657220416E-
 3609 0000148D 76696E
 3610 00001490 0D0A00                                  db 0Dh, 0Ah, 0
 3611 00001493 626F6F743A2000          boot_prompt     db 'boot: ', 0
 3612 0000149A 08200800                wipe_char       db 08h, ' ', 08h, 0
 3613 0000149E 436F756C64206E6F74-     err_notfound    db 'Could not find kernel image: ',0
 3614 000014A7 2066696E64206B6572-
 3615 000014B0 6E656C20696D616765-
 3616 000014B9 3A2000
 3617 000014BC 0D0A496E76616C6964-     err_notkernel   db 0Dh, 0Ah, 'Invalid or corrupt kernel image.', 0Dh, 0Ah, 0
 3618 000014C5 206F7220636F727275-
 3619 000014CE 7074206B65726E656C-
 3620 000014D7 20696D6167652E0D0A-
 3621 000014E0 00
 3622 000014E1 497420617070656172-     err_not386      db 'It appears your computer uses a 286 or lower CPU.'
 3623 000014EA 7320796F757220636F-
 3624 000014F3 6D7075746572207573-
 3625 000014FC 657320612032383620-
 3626 00001505 6F72206C6F77657220-
 3627 0000150E 4350552E
 3628 00001512 0D0A                                    db 0Dh, 0Ah
 3629 00001514 596F752063616E6E6F-                     db 'You cannot run Linux unless you have a 386 or higher CPU'
 3630 0000151D 742072756E204C696E-
 3631 00001526 757820756E6C657373-
 3632 0000152F 20796F752068617665-
 3633 00001538 206120333836206F72-
 3634 00001541 206869676865722043-
 3635 0000154A 5055
 3636 0000154C 0D0A                                    db 0Dh, 0Ah
 3637 0000154E 696E20796F7572206D-                     db 'in your machine.  If you get this message in error, hold'
 3638 00001557 616368696E652E2020-
 3639 00001560 496620796F75206765-
 3640 00001569 742074686973206D65-
 3641 00001572 737361676520696E20-
 3642 0000157B 6572726F722C20686F-
 3643 00001584 6C64
 3644 00001586 0D0A                                    db 0Dh, 0Ah
 3645 00001588 646F776E2074686520-                     db 'down the Ctrl key while booting, and I will take your'
 3646 00001591 4374726C206B657920-
 3647 0000159A 7768696C6520626F6F-
 3648 000015A3 74696E672C20616E64-
 3649 000015AC 20492077696C6C2074-
 3650 000015B5 616B6520796F7572
 3651 000015BD 0D0A                                    db 0Dh, 0Ah
 3652 000015BF 776F726420666F7220-                     db 'word for it.', 0Dh, 0Ah, 0
 3653 000015C8 69742E0D0A00
 3654 000015CE 497420617070656172-     err_noram       db 'It appears your computer has less than 608K of low ("DOS")'
 3655 000015D7 7320796F757220636F-
 3656 000015E0 6D7075746572206861-
 3657 000015E9 73206C657373207468-
 3658 000015F2 616E203630384B206F-
 3659 000015FB 66206C6F7720282244-
 3660 00001604 4F532229
 3661 00001608 0D0A                                    db 0Dh, 0Ah
 3662 0000160A 52414D2E20204C696E-                     db 'RAM.  Linux needs at least this amount to boot.  If you get'
 3663 00001613 7578206E6565647320-
 3664 0000161C 6174206C6561737420-
 3665 00001625 7468697320616D6F75-
 3666 0000162E 6E7420746F20626F6F-
 3667 00001637 742E2020496620796F-
 3668 00001640 7520676574
 3669 00001645 0D0A                                    db 0Dh, 0Ah
 3670 00001647 74686973206D657373-                     db 'this message in error, hold down the Ctrl key while'
 3671 00001650 61676520696E206572-
 3672 00001659 726F722C20686F6C64-
 3673 00001662 20646F776E20746865-
 3674 0000166B 204374726C206B6579-
 3675 00001674 207768696C65
 3676 0000167A 0D0A                                    db 0Dh, 0Ah
 3677 0000167C 626F6F74696E672C20-                     db 'booting, and I will take your word for it.', 0Dh, 0Ah, 0
 3678 00001685 616E6420492077696C-
 3679 0000168E 6C2074616B6520796F-
 3680 00001697 757220776F72642066-
 3681 000016A0 6F722069742E0D0A00
 3682 000016A9 556E6B6E6F776E206B-     err_badcfg      db 'Unknown keyword in syslinux.cfg.', 0Dh, 0Ah, 0
 3683 000016B2 6579776F726420696E-
 3684 000016BB 207379736C696E7578-
 3685 000016C4 2E6366672E0D0A00
 3686 000016CC 4D697373696E672070-     err_noparm      db 'Missing parameter in syslinux.cfg.', 0Dh, 0Ah, 0
 3687 000016D5 6172616D6574657220-
 3688 000016DE 696E207379736C696E-
 3689 000016E7 75782E6366672E0D0A-
 3690 000016F0 00
 3691 000016F1 0D0A436F756C64206E-     err_noinitrd    db 0Dh, 0Ah, 'Could not find ramdisk image: ', 0
 3692 000016FA 6F742066696E642072-
 3693 00001703 616D6469736B20696D-
 3694 0000170C 6167653A2000
 3695 00001712 4E6F7420656E6F7567-     err_nohighmem   db 'Not enough memory to load specified kernel.', 0Dh, 0Ah, 0
 3696 0000171B 68206D656D6F727920-
 3697 00001724 746F206C6F61642073-
 3698 0000172D 706563696669656420-
 3699 00001736 6B65726E656C2E0D0A-
 3700 0000173F 00
 3701 00001740 0D0A4B65726E656C20-     err_highload    db 0Dh, 0Ah, 'Kernel transfer failure.', 0Dh, 0Ah, 0
 3702 00001749 7472616E7366657220-
 3703 00001752 6661696C7572652E0D-
 3704 0000175B 0A00
 3705 0000175D 43616E6E6F74206C6F-     err_oldkernel   db 'Cannot load a ramdisk with an old kernel image.'
 3706 00001766 616420612072616D64-
 3707 0000176F 69736B207769746820-
 3708 00001778 616E206F6C64206B65-
 3709 00001781 726E656C20696D6167-
 3710 0000178A 652E
 3711 0000178C 0D0A00                                  db 0Dh, 0Ah, 0
 3712 0000178F 3A20617474656D7074-     err_notdos      db ': attempted DOS system call', 0Dh, 0Ah, 0
 3713 00001798 656420444F53207379-
 3714 000017A1 7374656D2063616C6C-
 3715 000017AA 0D0A00
 3716 000017AD 434F4D424F4F542069-     err_comlarge    db 'COMBOOT image too large.', 0Dh, 0Ah, 0
 3717 000017B6 6D61676520746F6F20-
 3718 000017BF 6C617267652E0D0A00
 3719 000017C8 496E76616C6964206F-     err_bootsec     db 'Invalid or corrupt boot sector image.', 0Dh, 0Ah, 0
 3720 000017D1 7220636F7272757074-
 3721 000017DA 20626F6F7420736563-
 3722 000017E3 746F7220696D616765-
 3723 000017EC 2E0D0A00
 3724 000017F0 0D0A41323020676174-     err_a20         db 0Dh, 0Ah, 'A20 gate not responding!', 0Dh, 0Ah, 0
 3725 000017F9 65206E6F7420726573-
 3726 00001802 706F6E64696E67210D-
 3727 0000180B 0A00
 3728 0000180D 0D0A426F6F74206661-     err_bootfailed  db 0Dh, 0Ah, 'Boot failed: please change disks and press '
 3729 00001816 696C65643A20706C65-
 3730 0000181F 617365206368616E67-
 3731 00001828 65206469736B732061-
 3732 00001831 6E6420707265737320
 3733 0000183A 61206B657920746F20-                     db 'a key to continue.', 0Dh, 0Ah, 0
 3734 00001843 636F6E74696E75652E-
 3735 0000184C 0D0A00
 3736 0000184F 4C6F6164696E672000      loading_msg     db 'Loading ', 0
 3737 00001858 2E                      dotdot_msg      db '.'
 3738 00001859 2E00                    dot_msg         db '.', 0
 3739 0000185B 2061626F727465642E      aborted_msg     db ' aborted.'                  ; Fall through to crlf_msg!
 3740 00001864 0D0A00                  crlf_msg        db 0Dh, 0Ah, 0
 3741 00001867 0D0C00                  crff_msg        db 0Dh, 0Ch, 0
 3742 0000186A 5359534C494E555843-     syslinux_cfg    db 'SYSLINUXCFG'
 3743 00001873 4647
 3744                                  ;
 3745                                  ; Command line options we'd like to take a look at
 3746                                  ;
 3747                                  ; mem= and vga= are handled as normal 32-bit integer values
 3748 00001875 696E697472643D          initrd_cmd      db 'initrd='
 3749                                  initrd_cmd_len  equ 7
 3750                                  ;
 3751                                  ; Config file keyword table
 3752                                  ;
 3753                                                  align 2
 3754 0000187C 6170                    keywd_table     db 'ap' ; append
 3755 0000187E 6465                                    db 'de' ; default
 3756 00001880 7469                                    db 'ti' ; timeout
 3757 00001882 666F                                    db 'fo' ; font
 3758 00001884 6B62                                    db 'kb' ; kbd
 3759 00001886 6469                                    db 'di' ; display
 3760 00001888 7072                                    db 'pr' ; prompt
 3761 0000188A 6C61                                    db 'la' ; label
 3762 0000188C 696D                                    db 'im' ; implicit
 3763 0000188E 6B65                                    db 'ke' ; kernel
 3764 00001890 7365                                    db 'se' ; serial
 3765 00001892 6631                                    db 'f1' ; F1
 3766 00001894 6632                                    db 'f2' ; F2
 3767 00001896 6633                                    db 'f3' ; F3
 3768 00001898 6634                                    db 'f4' ; F4
 3769 0000189A 6635                                    db 'f5' ; F5
 3770 0000189C 6636                                    db 'f6' ; F6
 3771 0000189E 6637                                    db 'f7' ; F7
 3772 000018A0 6638                                    db 'f8' ; F8
 3773 000018A2 6639                                    db 'f9' ; F9
 3774 000018A4 6630                                    db 'f0' ; F10
 3775 000018A6 0000                                    dw 0
 3776                                  ;
 3777                                  ; Extensions to search for (in *reverse* order).  Note that the last
 3778                                  ; (lexically first) entry in the table is a placeholder for the original
 3779                                  ; extension, needed for error messages.  The exten_table is shifted so
 3780                                  ; the table is 1-based; this is because a "loop" cx is used as index.
 3781                                  ;
 3782                                  exten_table:
 3783 000018A8 00000000                OrigKernelExt:  dd 0                    ; Original extension
 3784 000018AC 434F4D00                                db 'COM',0              ; COMBOOT (same as DOS)
 3785 000018B0 42532000                                db 'BS ',0              ; Boot Sector
 3786 000018B4 42535300                                db 'BSS',0              ; Boot Sector (add superblock)
 3787 000018B8 43425400                                db 'CBT',0              ; COMBOOT (specific)
 3788
 3789                                  exten_count     equ (($-exten_table) >> 2) - 1  ; Number of alternates
 3790                                  ;
 3791                                  ; Misc initialized (data) variables
 3792                                  ;
 3793 000018BC 0000                    AppendLen       dw 0                    ; Bytes in append= command
 3794 000018BE 0000                    KbdTimeOut      dw 0                    ; Keyboard timeout (if any)
 3795 000018C0 0000                    FKeyMap         dw 0                    ; Bitmap for F-keys loaded
 3796 000018C2 0080                    CmdLinePtr      dw cmd_line_here        ; Command line advancing pointer
 3797                                  initrd_flag     equ $
 3798 000018C4 0000                    initrd_ptr      dw 0                    ; Initial ramdisk pointer/flag
 3799 000018C6 0000                    VKernelCtr      dw 0                    ; Number of registered vkernels
 3800 000018C8 0000                    ForcePrompt     dw 0                    ; Force prompt
 3801 000018CA 0100                    AllowImplicit   dw 1                    ; Allow implicit kernels
 3802 000018CC 0000                    SerialPort      dw 0                    ; Serial port base (or 0 for no serial port)
 3803                                  ;
 3804                                  ; Stuff for the command line; we do some trickery here with equ to avoid
 3805                                  ; tons of zeros appended to our file and wasting space
 3806                                  ;
 3807 000018CE 6C696E757820            linuxauto_cmd   db 'linux '
 3808 000018D4 6175746F00              auto_cmd        db 'auto',0
 3809                                  linuxauto_len   equ $-linuxauto_cmd
 3810                                  auto_len        equ $-auto_cmd
 3811 000018D9 424F4F545F494D4147-     boot_image      db 'BOOT_IMAGE='
 3812 000018E2 453D
 3813                                  boot_image_len  equ $-boot_image
 3814                                                  align 4, db 0           ; For the good of REP MOVSD
 3815                                  command_line    equ $
 3816                                  default_cmd     equ $+(max_cmd_len+2)
 3817                                  ldlinux_end     equ default_cmd+(max_cmd_len+1)
 3818                                  kern_cmd_len    equ ldlinux_end-command_line
 3819                                  ldlinux_len     equ ldlinux_end-ldlinux_magic
 3820                                  ;
 3821                                  ; Put the getcbuf right after the code, aligned on a sector boundary
 3822                                  ;
 3823                                  end_of_code     equ (ldlinux_end-bootsec)+7C00h
 3824                                  getcbuf         equ (end_of_code + 511) & 0FE00h