1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
|
; -*- fundamental -*- (asm-mode sucks)
; -----------------------------------------------------------------------
;
; Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
; Boston MA 02111-1307, USA; either version 2 of the License, or
; (at your option) any later version; incorporated herein by reference.
;
; -----------------------------------------------------------------------
;
; copybs.asm
;
; Small DOS program to copy the boot sector from a drive
; to a file
;
; Usage: copybs <drive>: <file>
;
absolute 0
pspInt20: resw 1
pspNextParagraph: resw 1
resb 1 ; reserved
pspDispatcher: resb 5
pspTerminateVector: resd 1
pspControlCVector: resd 1
pspCritErrorVector: resd 1
resw 11 ; reserved
pspEnvironment: resw 1
resw 23 ; reserved
pspFCB_1: resb 16
pspFCB_2: resb 16
resd 1 ; reserved
pspCommandLen: resb 1
pspCommandArg: resb 127
section .text
org 100h ; .COM format
_start:
mov ax,3000h ; Get DOS version
int 21h
xchg al,ah
mov [DOSVersion],ax
cmp ax,0200h ; DOS 2.00 minimum
jae dosver_ok
mov dx,msg_ancient_err
jmp die
section .bss
alignb 2
DOSVersion: resw 1
section .text
;
; Scan command line for a drive letter followed by a colon
;
dosver_ok:
xor cx,cx
mov si,pspCommandArg
mov cl,[pspCommandLen]
cmdscan1: jcxz bad_usage ; End of command line?
lodsb ; Load character
dec cx
cmp al,' ' ; White space
jbe cmdscan1
or al,020h ; -> lower case
cmp al,'a' ; Check for letter
jb bad_usage
cmp al,'z'
ja bad_usage
sub al,'a' ; Convert to zero-based index
mov [DriveNo],al ; Save away drive index
section .bss
DriveNo: resb 1
section .text
;
; Got the leading letter, now the next character must be a colon
;
got_letter: jcxz bad_usage
lodsb
dec cx
cmp al,':'
jne bad_usage
;
; Got the colon; now we should have at least one whitespace
; followed by a filename
;
got_colon: jcxz bad_usage
lodsb
dec cx
cmp al,' '
ja bad_usage
skipspace: jcxz bad_usage
lodsb
dec cx
cmp al,' '
jbe skipspace
mov di,FileName
copyfile: stosb
jcxz got_cmdline
lodsb
dec cx
cmp al,' '
ja copyfile
jmp short got_cmdline
;
; We end up here if the command line doesn't parse
;
bad_usage: mov dx,msg_unfair
jmp die
section .data
msg_unfair: db 'Usage: copybs <drive>: <filename>', 0Dh, 0Ah, '$'
section .bss
alignb 4
FileName resb 256
;
; Parsed the command line OK. Get device parameter block to get the
; sector size.
;
struc DPB
dpbDrive: resb 1
dpbUnit: resb 1
dpbSectorSize: resw 1
dpbClusterMask: resb 1
dpbClusterShift: resb 1
dpbFirstFAT: resw 1
dpbFATCount: resb 1
dpbRootEntries: resw 1
dpbFirstSector: resw 1
dpbMaxCluster: resw 1
dpbFATSize: resw 1
dpbDirSector: resw 1
dpbDriverAddr: resd 1
dpbMedia: resb 1
dpbFirstAccess: resb 1
dpbNextDPB: resd 1
dpbNextFree: resw 1
dpbFreeCnt: resw 1
endstruc
section .bss
alignb 2
SectorSize resw 1
section .text
got_cmdline:
xor al,al ; Zero-terminate filename
stosb
mov dl,[DriveNo]
inc dl ; 1-based
mov ah,32h
int 21h ; Get Drive Parameter Block
and al,al
jnz filesystem_error
mov dx,[bx+dpbSectorSize] ; Save sector size
;
; Read the boot sector.
;
section .data
align 4, db 0
DISKIO equ $
diStartSector: dd 0 ; Absolute sector 0
diSectors: dw 1 ; One sector
diBuffer: dw SectorBuffer ; Buffer offset
dw 0 ; Buffer segment
section .text
read_bootsect:
mov ax,cs ; Set DS <- CS
mov ds,ax
mov [SectorSize],dx ; Saved sector size from above
cmp word [DOSVersion],0400h ; DOS 4.00 has a new interface
jae .new
.old:
mov bx,SectorBuffer
mov cx,1 ; One sector
jmp short .common
.new:
mov [diBuffer+2],ax ; == DS
mov bx,DISKIO
mov cx,-1
.common:
xor dx,dx ; Absolute sector 0
mov al,[DriveNo]
int 25h ; DOS absolute disk read
pop ax ; Remove flags from stack
jc disk_read_error
;
; Open the file and write the boot sector to the file.
;
mov dx,FileName
mov cx,0020h ; Attribute = ARCHIVE
mov ah,3Ch ; Create file
int 21h
jc file_write_error
mov bx,ax
push ax ; Handle
mov cx,[SectorSize]
mov dx,SectorBuffer
mov ah,40h ; Write file
int 21h
jc file_write_error
cmp ax,[SectorSize]
jne file_write_error
pop bx ; Handle
mov ah,3Eh ; Close file
int 21h
jc file_write_error
;
; We're done!
;
mov ax,4C00h ; exit(0)
int 21h
;
; Error routine jump
;
filesystem_error:
mov dx,msg_filesystem_err
jmp short die
disk_read_error:
mov dx,msg_read_err
jmp short die
file_write_error:
mov dx,msg_write_err
die:
push cs
pop ds
push dx
mov dx,msg_error
mov ah,09h
int 21h
pop dx
mov ah,09h ; Write string
int 21h
mov ax,4C01h ; Exit error status
int 21h
section .data
msg_error: db 'ERROR: $'
msg_ancient_err: db 'DOS version 2.00 or later required', 0Dh, 0Ah, '$'
msg_filesystem_err: db 'Filesystem not found on disk', 0Dh, 0Ah, '$'
msg_read_err: db 'Boot sector read failed', 0Dh, 0Ah, '$'
msg_write_err: db 'File write failed', 0Dh, 0Ah, '$'
section .bss
alignb 4
SectorBuffer: resb 4096
|