summaryrefslogtreecommitdiff
path: root/copybs.asm
blob: 26407148b2511ce69120204d712bbafe6df49f71 (plain)
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