     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
