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