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 pspInt20: resw 1 23 00000002 pspNextParagraph: resw 1 24 00000004 resb 1 ; reserved 25 00000005 pspDispatcher: resb 5 26 0000000A pspTerminateVector: resd 1 27 0000000E pspControlCVector: resd 1 28 00000012 pspCritErrorVector: resd 1 29 00000016 resw 11 ; reserved 30 0000002C pspEnvironment: resw 1 31 0000002E resw 23 ; reserved 32 0000005C pspFCB_1: resb 16 33 0000006C pspFCB_2: resb 16 34 0000007C resd 1 ; reserved 35 00000080 pspCommandLen: resb 1 36 00000081 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 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] :', 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 dpbDrive: resb 1 122 00000001 dpbUnit: resb 1 123 00000002 dpbSectorSize: resw 1 124 00000004 dpbClusterMask: resb 1 125 00000005 dpbClusterShift: resb 1 126 00000006 dpbFirstFAT: resw 1 127 00000008 dpbFATCount: resb 1 128 00000009 dpbRootEntries: resw 1 129 0000000B dpbFirstSector: resw 1 130 0000000D dpbMaxCluster: resw 1 131 0000000F dpbFATSize: resw 1 132 00000011 dpbDirSector: resw 1 133 00000013 dpbDriverAddr: resd 1 134 00000017 dpbMedia: resb 1 135 00000018 dpbFirstAccess: resb 1 136 00000019 dpbNextDPB: resd 1 137 0000001D dpbNextFree: resw 1 138 0000001F 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 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 BootSector: incbin "bootsect.bin" 329 000000DE LDLinuxSYS: incbin "ldlinux.sys" 330 ldlinux_size: equ $-LDLinuxSYS 331 332 section .bss 333 00000003 alignb 4 334 00000004 SectorBuffer: resb 512