     1                                  ; -*- fundamental -*- (asm-mode sucks)
     2                                  ; $Id: syslinux.asm,v 1.8 1998/04/14 06:28:08 hpa Exp $
     3                                  ; -----------------------------------------------------------------------
     4                                  ;   
     5                                  ;   Copyright 1998 H. Peter Anvin - All Rights Reserved
     6                                  ;
     7                                  ;   This program is free software; you can redistribute it and/or modify
     8                                  ;   it under the terms of the GNU General Public License as published by
     9                                  ;   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
    10                                  ;   USA; either version 2 of the License, or (at your option) any later
    11                                  ;   version; incorporated herein by reference.
    12                                  ;
    13                                  ; -----------------------------------------------------------------------
    14                                  
    15                                  ;
    16                                  ; syslinux.asm
    17                                  ;
    18                                  ;	DOS installer for SYSLINUX
    19                                  ;
    20                                  
    21                                  		absolute 0
    22 00000000 <res 00000002>          pspInt20:		resw 1
    23 00000002 <res 00000002>          pspNextParagraph:	resw 1
    24 00000004 <res 00000001>          			resb 1		; reserved
    25 00000005 <res 00000005>          pspDispatcher:		resb 5
    26 0000000A <res 00000004>          pspTerminateVector:	resd 1
    27 0000000E <res 00000004>          pspControlCVector:	resd 1
    28 00000012 <res 00000004>          pspCritErrorVector:	resd 1
    29 00000016 <res 00000016>          			resw 11		; reserved
    30 0000002C <res 00000002>          pspEnvironment:		resw 1
    31 0000002E <res 0000002E>          			resw 23		; reserved
    32 0000005C <res 00000010>          pspFCB_1:		resb 16
    33 0000006C <res 00000010>          pspFCB_2:		resb 16
    34 0000007C <res 00000004>          			resd 1		; reserved
    35 00000080 <res 00000001>          pspCommandLen:		resb 1
    36 00000081 <res 0000007F>          pspCommandArg:		resb 127
    37                                  
    38                                  		section .text
    39                                  		org 0100h
    40                                  _start:		
    41                                  		; BUG: check DOS version
    42                                  
    43                                  ;
    44                                  ; Scan command line for a drive letter followed by a colon
    45                                  ;
    46 00000000 31C9                    		xor cx,cx
    47 00000002 BE8100                  		mov si,pspCommandArg
    48 00000005 8A0E8000                		mov cl,[pspCommandLen]
    49                                  		
    50 00000009 E329                    cmdscan1:	jcxz bad_usage			; End of command line?
    51 0000000B AC                      		lodsb				; Load character
    52 0000000C 49                      		dec cx
    53 0000000D 3C20                    		cmp al,' '			; White space
    54 0000000F 76F8                    		jbe cmdscan1
    55 00000011 3C2D                    		cmp al,'-'
    56 00000013 7425                    		je scan_option
    57 00000015 0C20                    		or al,020h			; -> lower case
    58 00000017 3C61                    		cmp al,'a'			; Check for letter
    59 00000019 7219                    		jb bad_usage
    60 0000001B 3C7A                    		cmp al,'z'
    61 0000001D 7715                    		ja bad_usage
    62 0000001F 2C61                    		sub al,'a'			; Convert to zero-based index
    63 00000021 A2[0000]                		mov [DriveNo],al		; Save away drive index
    64                                  
    65                                  		section .bss
    66 00000000 <res 00000001>          DriveNo:	resb 1
    67                                  
    68                                  		section .text
    69                                  ;
    70                                  ; Got the leading letter, now the next character must be a colon
    71                                  ;
    72 00000024 E30E                    got_letter:	jcxz bad_usage
    73 00000026 AC                      		lodsb
    74 00000027 49                      		dec cx
    75 00000028 3C3A                    		cmp al,':'
    76 0000002A 7508                    		jne bad_usage
    77                                  ;
    78                                  ; Got the colon; the rest better be whitespace
    79                                  ;
    80 0000002C E323                    got_colon:	jcxz got_cmdline
    81 0000002E AC                      		lodsb
    82 0000002F 49                      		dec cx
    83 00000030 3C20                    		cmp al,' '
    84 00000032 76F8                    		jbe got_colon
    85                                  ;
    86                                  ; We end up here if the command line doesn't parse
    87                                  ;
    88 00000034 BA[0000]                bad_usage:	mov dx,msg_unfair
    89 00000037 E9D100                  		jmp die
    90                                  
    91                                  		section .data
    92 00000000 55736167653A207379-     msg_unfair:	db 'Usage: syslinux [-s] <drive>:', 0Dh, 0Ah, '$'
    93 00000009 736C696E7578205B2D-
    94 00000012 735D203C6472697665-
    95 0000001B 3E3A0D0A24         
    96                                  
    97                                  		section .text
    98                                  ;
    99                                  ; Scan for options after a - sign.  The only recognized option right now
   100                                  ; is -s.
   101                                  ;
   102 0000003A E3F8                    scan_option:	jcxz bad_usage
   103 0000003C AC                      		lodsb
   104 0000003D 49                      		dec cx
   105 0000003E 3C20                    		cmp al,' '
   106 00000040 76C7                    		jbe cmdscan1
   107 00000042 0C20                    		or al,20h
   108 00000044 3C73                    		cmp al,'s'
   109 00000046 75EC                    		jne bad_usage
   110 00000048 56                      		push si			; make_stupid doesn't save these
   111 00000049 51                      		push cx
   112 0000004A E8D200                  		call make_stupid	; Enable stupid boot sector
   113 0000004D 59                      		pop cx
   114 0000004E 5E                      		pop si
   115 0000004F EBE9                    		jmp short scan_option
   116                                  
   117                                  ;
   118                                  ; Parsed the command line OK.  Check that the drive parameters are acceptable
   119                                  ;
   120                                  		struc DPB
   121 00000000 <res 00000001>          dpbDrive:	resb 1
   122 00000001 <res 00000001>          dpbUnit:	resb 1
   123 00000002 <res 00000002>          dpbSectorSize:	resw 1
   124 00000004 <res 00000001>          dpbClusterMask:	resb 1
   125 00000005 <res 00000001>          dpbClusterShift: resb 1
   126 00000006 <res 00000002>          dpbFirstFAT:	resw 1
   127 00000008 <res 00000001>          dpbFATCount:	resb 1
   128 00000009 <res 00000002>          dpbRootEntries:	resw 1
   129 0000000B <res 00000002>          dpbFirstSector:	resw 1
   130 0000000D <res 00000002>          dpbMaxCluster:	resw 1
   131 0000000F <res 00000002>          dpbFATSize:	resw 1
   132 00000011 <res 00000002>          dpbDirSector:	resw 1
   133 00000013 <res 00000004>          dpbDriverAddr:	resd 1
   134 00000017 <res 00000001>          dpbMedia:	resb 1
   135 00000018 <res 00000001>          dpbFirstAccess:	resb 1
   136 00000019 <res 00000004>          dpbNextDPB:	resd 1
   137 0000001D <res 00000002>          dpbNextFree:	resw 1
   138 0000001F <res 00000002>          dpbFreeCnt:	resw 1
   139                                  		endstruc
   140                                  
   141                                  got_cmdline:
   142 00000051 8A16[0000]              		mov dl,[DriveNo]
   143 00000055 FEC2                    		inc dl				; 1-based
   144 00000057 BB0000                  		mov bx,DPB
   145 0000005A B432                    		mov ah,32h
   146 0000005C CD21                    		int 21h				; Get Drive Parameter Block
   147                                  		
   148 0000005E 20C0                    		and al,al
   149 00000060 7513                    		jnz filesystem_error
   150                                  
   151 00000062 817F020002              		cmp word [bx+dpbSectorSize],512	; Sector size = 512 required
   152 00000067 7512                    		jne sectorsize_error
   153                                  
   154 00000069 807F0505                		cmp byte [bx+dpbClusterShift],5	; Max size = 16K = 2^5 sectors
   155 0000006D 7612                    		jna read_bootsect
   156                                  
   157                                  hugeclust_error:
   158 0000006F BA[9000]                		mov dx,msg_hugeclust_err
   159 00000072 E99600                  		jmp die
   160                                  filesystem_error:
   161 00000075 BA[3F00]                		mov dx,msg_filesystem_err
   162 00000078 E99000                  		jmp die
   163                                  sectorsize_error:
   164 0000007B BA[5E00]                		mov dx,msg_sectorsize_err
   165 0000007E E98A00                  		jmp die
   166                                  
   167                                  ;
   168                                  ; Good enough.  Now read the old boot sector and copy the superblock.
   169                                  ;
   170                                  read_bootsect:
   171 00000081 0E                      		push cs				; Set DS == ES
   172 00000082 1F                      		pop ds
   173                                  
   174 00000083 BB[0400]                		mov bx,SectorBuffer
   175 00000086 A0[0000]                		mov al,[DriveNo]
   176 00000089 B90100                  		mov cx,1			; One sector
   177 0000008C 31D2                    		xor dx,dx			; Absolute sector 0
   178 0000008E CD25                    		int 25h				; DOS absolute disk read
   179 00000090 83C402                  		add sp,byte 2			; Remove flags from stack
   180 00000093 726E                    		jc disk_read_error
   181                                  
   182 00000095 BE[0F00]                		mov si,SectorBuffer+11		; Offset of superblock
   183 00000098 BF[EB00]                		mov di,BootSector+11
   184 0000009B B93300                  		mov cx,51			; Superblock = 51 bytes
   185 0000009E F3A4                    		rep movsb			; Copy the superblock
   186                                  ;
   187                                  ; Writing LDLINUX.SYS
   188                                  ;
   189                                  		; 0. Set the correct filename
   190                                  
   191 000000A0 A0[0000]                		mov al,[DriveNo]
   192 000000A3 0006[2000]              		add [ldlinux_sys_str],al
   193                                  
   194                                  		; 1. If the file exists, strip its attributes and delete
   195                                  
   196 000000A7 31C9                    		xor cx,cx			; Clear attributes
   197 000000A9 BA[2000]                		mov dx,ldlinux_sys_str
   198 000000AC B80143                  		mov ax,4301h			; Set file attributes
   199 000000AF CD21                    		int 21h
   200                                  
   201 000000B1 BA[2000]                		mov dx,ldlinux_sys_str
   202 000000B4 B441                    		mov ah,41h			; Delete file
   203 000000B6 CD21                    		int 21h
   204                                  
   205                                  		section .data
   206 00000020 413A5C4C444C494E55-     ldlinux_sys_str: db 'A:\LDLINUX.SYS', 0
   207 00000029 582E53595300       
   208                                  
   209                                  		section .text
   210                                  
   211                                  		; 2. Create LDLINUX.SYS and write data to it
   212                                  
   213 000000B8 BA[2000]                		mov dx,ldlinux_sys_str
   214 000000BB 31C9                    		xor cx,cx			; Normal file
   215 000000BD B43C                    		mov ah,3Ch			; Create file
   216 000000BF CD21                    		int 21h
   217 000000C1 7245                    		jc file_write_error
   218 000000C3 A3[0100]                		mov [FileHandle],ax
   219                                  
   220 000000C6 89C3                    		mov bx,ax
   221 000000C8 B9BC12                  		mov cx,ldlinux_size
   222 000000CB BA[E002]                		mov dx,LDLinuxSYS
   223 000000CE B440                    		mov ah,40h			; Write data
   224 000000D0 CD21                    		int 21h
   225 000000D2 7234                    		jc file_write_error
   226 000000D4 3DBC12                  		cmp ax,ldlinux_size
   227 000000D7 752F                    		jne file_write_error
   228                                  
   229 000000D9 8B1E[0100]              		mov bx,[FileHandle]
   230 000000DD B43E                    		mov ah,3Eh			; Close file
   231 000000DF CD21                    		int 21h
   232                                  
   233                                  		section .bss
   234 00000001 <res 00000002>          FileHandle:	resw 1
   235                                  
   236                                  		section .text
   237                                  
   238                                  		; 3. Set the readonly flag on LDLINUX.SYS
   239                                  
   240 000000E1 BA[2000]                		mov dx,ldlinux_sys_str
   241 000000E4 B90100                  		mov cx,1			; Read only
   242 000000E7 B80143                  		mov ax,4301h			; Set attributes
   243 000000EA CD21                    		int 21h
   244                                  ;
   245                                  ; Writing boot sector
   246                                  ;
   247 000000EC A0[0000]                		mov al,[DriveNo]
   248 000000EF BB[E000]                		mov bx,BootSector
   249 000000F2 B90100                  		mov cx,1			; One sector
   250 000000F5 31D2                    		xor dx,dx			; Absolute sector 0
   251 000000F7 CD26                    		int 26h				; DOS absolute disk write
   252 000000F9 83C402                  		add sp,byte 2			; Remove flags
   253 000000FC 720A                    		jc disk_write_error
   254                                  
   255 000000FE B8004C                  all_done:	mov ax,4C00h			; Exit good status
   256 00000101 CD21                    		int 21h
   257                                  ;
   258                                  ; Error routine jump
   259                                  ;
   260                                  disk_read_error:
   261 00000103 BA[B900]                		mov dx,msg_read_err
   262 00000106 EB03                    		jmp short die
   263                                  disk_write_error:
   264                                  file_write_error:
   265 00000108 BA[CC00]                		mov dx,msg_write_err
   266                                  die:
   267 0000010B 0E                      		push cs
   268 0000010C 1F                      		pop ds
   269 0000010D 52                      		push dx
   270 0000010E BA[3700]                		mov dx,msg_error
   271 00000111 B409                    		mov ah,09h
   272 00000113 CD21                    		int 21h
   273 00000115 5A                      		pop dx
   274                                  
   275 00000116 B409                    		mov ah,09h			; Write string
   276 00000118 CD21                    		int 21h
   277                                  
   278 0000011A B8014C                  		mov ax,4C01h			; Exit error status
   279 0000011D CD21                    		int 21h
   280                                  
   281                                  ;
   282                                  ; This includes a small subroutine make_stupid to patch up the boot sector
   283                                  ; in case we give the -s (stupid) option
   284                                  ;
   285                                  		%include "stupid.inc"
   286                              <1> 	section .text
   287                              <1> make_stupid:
   288 0000011F BE[2F00]            <1> 	mov si, .stupid_patch
   289 00000122 BF[5C02]            <1> 	mov di, BootSector+017Ch
   290 00000125 B90800              <1> 	mov cx, 8
   291 00000128 F3A4                <1> 	rep movsb
   292 0000012A C3                  <1> 	ret
   293                              <1> 	section .data
   294                              <1> .stupid_patch:
   295 0000002F BD0100              <1> 	mov bp,1
   296 00000032 90                  <1> 	nop
   297 00000033 90                  <1> 	nop
   298 00000034 90                  <1> 	nop
   299 00000035 90                  <1> 	nop
   300 00000036 90                  <1> 	nop
   301                                  
   302                                  		section .data
   303 00000037 4552524F523A2024        msg_error:		db 'ERROR: $'
   304 0000003F 46696C657379737465-     msg_filesystem_err:	db 'Filesystem not found on disk', 0Dh, 0Ah, '$'
   305 00000048 6D206E6F7420666F75-
   306 00000051 6E64206F6E20646973-
   307 0000005A 6B0D0A24           
   308 0000005E 536563746F72207369-     msg_sectorsize_err:	db 'Sector sizes other than 512 bytes not supported', 0Dh, 0Ah, '$'
   309 00000067 7A6573206F74686572-
   310 00000070 207468616E20353132-
   311 00000079 206279746573206E6F-
   312 00000082 7420737570706F7274-
   313 0000008B 65640D0A24         
   314 00000090 436C75737465727320-     msg_hugeclust_err:	db 'Clusters larger than 16K not supported', 0Dh, 0Ah, '$'
   315 00000099 6C6172676572207468-
   316 000000A2 616E2031364B206E6F-
   317 000000AB 7420737570706F7274-
   318 000000B4 65640D0A24         
   319 000000B9 4469736B2072656164-     msg_read_err:		db 'Disk read failed', 0Dh, 0Ah, '$'
   320 000000C2 206661696C65640D0A-
   321 000000CB 24                 
   322 000000CC 4469736B2077726974-     msg_write_err:		db 'Disk write failed', 0Dh, 0Ah, '$'
   323 000000D5 65206661696C65640D-
   324 000000DE 0A24               
   325                                  
   326                                  		section .data
   327                                  		align 4, db 0
   328 000000DE <incbin>                BootSector:	incbin "bootsect.bin"
   329 000000DE <incbin>                LDLinuxSYS:	incbin "ldlinux.sys"
   330                                  ldlinux_size:	equ $-LDLinuxSYS
   331                                  
   332                                  		section .bss
   333 00000003 <res 00000001>          		alignb 4
   334 00000004 <res 00000200>          SectorBuffer:	resb 512
