1 ; -*- fundamental -*- (asm-mode sucks) 2 ; ----------------------------------------------------------------------- 3 ; 4 ; Copyright 1998-2008 H. Peter Anvin - All Rights Reserved 5 ; 6 ; This program is free software; you can redistribute it and/or modify 7 ; it under the terms of the GNU General Public License as published by 8 ; the Free Software Foundation, Inc., 53 Temple Place Ste 330, 9 ; Boston MA 02111-1307, USA; either version 2 of the License, or 10 ; (at your option) any later version; incorporated herein by reference. 11 ; 12 ; ----------------------------------------------------------------------- 13 14 ; 15 ; copybs.asm 16 ; 17 ; Small DOS program to copy the boot sector from a drive 18 ; to a file 19 ; 20 ; Usage: copybs : 21 ; 22 23 absolute 0 24 00000000 pspInt20: resw 1 25 00000002 pspNextParagraph: resw 1 26 00000004 resb 1 ; reserved 27 00000005 pspDispatcher: resb 5 28 0000000A pspTerminateVector: resd 1 29 0000000E pspControlCVector: resd 1 30 00000012 pspCritErrorVector: resd 1 31 00000016 resw 11 ; reserved 32 0000002C pspEnvironment: resw 1 33 0000002E resw 23 ; reserved 34 0000005C pspFCB_1: resb 16 35 0000006C pspFCB_2: resb 16 36 0000007C resd 1 ; reserved 37 00000080 pspCommandLen: resb 1 38 00000081 pspCommandArg: resb 127 39 40 section .text 41 org 100h ; .COM format 42 _start: 43 00000000 B80030 mov ax,3000h ; Get DOS version 44 00000003 CD21 int 21h 45 00000005 86C4 xchg al,ah 46 00000007 A3[0000] mov [DOSVersion],ax 47 0000000A 3D0002 cmp ax,0200h ; DOS 2.00 minimum 48 0000000D 7306 jae dosver_ok 49 0000000F BA[3600] mov dx,msg_ancient_err 50 00000012 E9C500 jmp die 51 52 section .bss 53 alignb 2 54 00000000 DOSVersion: resw 1 55 56 section .text 57 ; 58 ; Scan command line for a drive letter followed by a colon 59 ; 60 dosver_ok: 61 00000015 31C9 xor cx,cx 62 00000017 BE8100 mov si,pspCommandArg 63 0000001A 8A0E8000 mov cl,[pspCommandLen] 64 65 0000001E E33B cmdscan1: jcxz bad_usage ; End of command line? 66 00000020 AC lodsb ; Load character 67 00000021 49 dec cx 68 00000022 3C20 cmp al,' ' ; White space 69 00000024 76F8 jbe cmdscan1 70 00000026 0C20 or al,020h ; -> lower case 71 00000028 3C61 cmp al,'a' ; Check for letter 72 0000002A 722F jb bad_usage 73 0000002C 3C7A cmp al,'z' 74 0000002E 772B ja bad_usage 75 00000030 2C61 sub al,'a' ; Convert to zero-based index 76 00000032 A2[0200] mov [DriveNo],al ; Save away drive index 77 78 section .bss 79 00000002 DriveNo: resb 1 80 81 section .text 82 ; 83 ; Got the leading letter, now the next character must be a colon 84 ; 85 00000035 E324 got_letter: jcxz bad_usage 86 00000037 AC lodsb 87 00000038 49 dec cx 88 00000039 3C3A cmp al,':' 89 0000003B 751E jne bad_usage 90 ; 91 ; Got the colon; now we should have at least one whitespace 92 ; followed by a filename 93 ; 94 0000003D E31C got_colon: jcxz bad_usage 95 0000003F AC lodsb 96 00000040 49 dec cx 97 00000041 3C20 cmp al,' ' 98 00000043 7716 ja bad_usage 99 100 00000045 E314 skipspace: jcxz bad_usage 101 00000047 AC lodsb 102 00000048 49 dec cx 103 00000049 3C20 cmp al,' ' 104 0000004B 76F8 jbe skipspace 105 106 0000004D BF[0400] mov di,FileName 107 00000050 AA copyfile: stosb 108 00000051 E30D jcxz got_cmdline 109 00000053 AC lodsb 110 00000054 49 dec cx 111 00000055 3C20 cmp al,' ' 112 00000057 77F7 ja copyfile 113 00000059 EB05 jmp short got_cmdline 114 115 ; 116 ; We end up here if the command line doesn't parse 117 ; 118 0000005B BA[0000] bad_usage: mov dx,msg_unfair 119 0000005E EB7A jmp die 120 121 section .data 122 00000000 55736167653A20636F- msg_unfair: db 'Usage: copybs : ', 0Dh, 0Ah, '$' 122 00000009 70796273203C647269- 122 00000012 76653E3A203C66696C- 122 0000001B 656E616D653E0D0A24 123 124 section .bss 125 00000003 alignb 4 126 00000004 FileName resb 256 127 128 ; 129 ; Parsed the command line OK. Get device parameter block to get the 130 ; sector size. 131 ; 132 struc DPB 133 00000000 dpbDrive: resb 1 134 00000001 dpbUnit: resb 1 135 00000002 dpbSectorSize: resw 1 136 00000004 dpbClusterMask: resb 1 137 00000005 dpbClusterShift: resb 1 138 00000006 dpbFirstFAT: resw 1 139 00000008 dpbFATCount: resb 1 140 00000009 dpbRootEntries: resw 1 141 0000000B dpbFirstSector: resw 1 142 0000000D dpbMaxCluster: resw 1 143 0000000F dpbFATSize: resw 1 144 00000011 dpbDirSector: resw 1 145 00000013 dpbDriverAddr: resd 1 146 00000017 dpbMedia: resb 1 147 00000018 dpbFirstAccess: resb 1 148 00000019 dpbNextDPB: resd 1 149 0000001D dpbNextFree: resw 1 150 0000001F dpbFreeCnt: resw 1 151 endstruc 152 153 section .bss 154 alignb 2 155 00000104 SectorSize resw 1 156 157 section .text 158 got_cmdline: 159 00000060 30C0 xor al,al ; Zero-terminate filename 160 00000062 AA stosb 161 162 00000063 8A16[0200] mov dl,[DriveNo] 163 00000067 FEC2 inc dl ; 1-based 164 00000069 B432 mov ah,32h 165 0000006B CD21 int 21h ; Get Drive Parameter Block 166 167 0000006D 20C0 and al,al 168 0000006F 755C jnz filesystem_error 169 170 00000071 8B5702 mov dx,[bx+dpbSectorSize] ; Save sector size 171 ; 172 ; Read the boot sector. 173 ; 174 section .data 175 align 4, db 0 176 DISKIO equ $ 177 00000024 00000000 diStartSector: dd 0 ; Absolute sector 0 178 00000028 0100 diSectors: dw 1 ; One sector 179 0000002A [0801] diBuffer: dw SectorBuffer ; Buffer offset 180 0000002C 0000 dw 0 ; Buffer segment 181 182 section .text 183 read_bootsect: 184 00000074 8CC8 mov ax,cs ; Set DS <- CS 185 00000076 8ED8 mov ds,ax 186 187 00000078 8916[0401] mov [SectorSize],dx ; Saved sector size from above 188 189 0000007C 813E[0000]0004 cmp word [DOSVersion],0400h ; DOS 4.00 has a new interface 190 00000082 7308 jae .new 191 .old: 192 00000084 BB[0801] mov bx,SectorBuffer 193 00000087 B90100 mov cx,1 ; One sector 194 0000008A EB09 jmp short .common 195 .new: 196 0000008C A3[2C00] mov [diBuffer+2],ax ; == DS 197 0000008F BB[2400] mov bx,DISKIO 198 00000092 B9FFFF mov cx,-1 199 .common: 200 00000095 31D2 xor dx,dx ; Absolute sector 0 201 00000097 A0[0200] mov al,[DriveNo] 202 0000009A CD25 int 25h ; DOS absolute disk read 203 0000009C 58 pop ax ; Remove flags from stack 204 0000009D 7233 jc disk_read_error 205 206 ; 207 ; Open the file and write the boot sector to the file. 208 ; 209 0000009F BA[0400] mov dx,FileName 210 000000A2 B92000 mov cx,0020h ; Attribute = ARCHIVE 211 000000A5 B43C mov ah,3Ch ; Create file 212 000000A7 CD21 int 21h 213 000000A9 722C jc file_write_error 214 215 000000AB 89C3 mov bx,ax 216 000000AD 50 push ax ; Handle 217 218 000000AE 8B0E[0401] mov cx,[SectorSize] 219 000000B2 BA[0801] mov dx,SectorBuffer 220 000000B5 B440 mov ah,40h ; Write file 221 000000B7 CD21 int 21h 222 000000B9 721C jc file_write_error 223 000000BB 3B06[0401] cmp ax,[SectorSize] 224 000000BF 7516 jne file_write_error 225 226 000000C1 5B pop bx ; Handle 227 000000C2 B43E mov ah,3Eh ; Close file 228 000000C4 CD21 int 21h 229 000000C6 720F jc file_write_error 230 ; 231 ; We're done! 232 ; 233 000000C8 B8004C mov ax,4C00h ; exit(0) 234 000000CB CD21 int 21h 235 236 ; 237 ; Error routine jump 238 ; 239 filesystem_error: 240 000000CD BA[5B00] mov dx,msg_filesystem_err 241 000000D0 EB08 jmp short die 242 disk_read_error: 243 000000D2 BA[7A00] mov dx,msg_read_err 244 000000D5 EB03 jmp short die 245 file_write_error: 246 000000D7 BA[9400] mov dx,msg_write_err 247 die: 248 000000DA 0E push cs 249 000000DB 1F pop ds 250 000000DC 52 push dx 251 000000DD BA[2E00] mov dx,msg_error 252 000000E0 B409 mov ah,09h 253 000000E2 CD21 int 21h 254 000000E4 5A pop dx 255 256 000000E5 B409 mov ah,09h ; Write string 257 000000E7 CD21 int 21h 258 259 000000E9 B8014C mov ax,4C01h ; Exit error status 260 000000EC CD21 int 21h 261 262 section .data 263 0000002E 4552524F523A2024 msg_error: db 'ERROR: $' 264 00000036 444F53207665727369- msg_ancient_err: db 'DOS version 2.00 or later required', 0Dh, 0Ah, '$' 264 0000003F 6F6E20322E3030206F- 264 00000048 72206C617465722072- 264 00000051 657175697265640D0A- 264 0000005A 24 265 0000005B 46696C657379737465- msg_filesystem_err: db 'Filesystem not found on disk', 0Dh, 0Ah, '$' 265 00000064 6D206E6F7420666F75- 265 0000006D 6E64206F6E20646973- 265 00000076 6B0D0A24 266 0000007A 426F6F742073656374- msg_read_err: db 'Boot sector read failed', 0Dh, 0Ah, '$' 266 00000083 6F7220726561642066- 266 0000008C 61696C65640D0A24 267 00000094 46696C652077726974- msg_write_err: db 'File write failed', 0Dh, 0Ah, '$' 267 0000009D 65206661696C65640D- 267 000000A6 0A24 268 269 section .bss 270 00000106 alignb 4 271 00000108 SectorBuffer: resb 4096