1 | ;; ----------------------------------------------------------------------- |
---|
2 | ;; |
---|
3 | ;; Copyright 2007-2008 H. Peter Anvin - All Rights Reserved |
---|
4 | ;; |
---|
5 | ;; This program is free software; you can redistribute it and/or modify |
---|
6 | ;; it under the terms of the GNU General Public License as published by |
---|
7 | ;; the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, |
---|
8 | ;; Boston MA 02110-1301, USA; either version 2 of the License, or |
---|
9 | ;; (at your option) any later version; incorporated herein by reference. |
---|
10 | ;; |
---|
11 | ;; ----------------------------------------------------------------------- |
---|
12 | |
---|
13 | ;; |
---|
14 | ;; adv.inc |
---|
15 | ;; |
---|
16 | ;; The auxillary data vector and its routines |
---|
17 | ;; |
---|
18 | ;; The auxillary data vector is a 512-byte aligned block that on the |
---|
19 | ;; disk-based derivatives can be part of the syslinux file itself. It |
---|
20 | ;; exists in two copies; when written, both copies are written (with a |
---|
21 | ;; sync in between, if from the operating system.) The first two |
---|
22 | ;; dwords are magic number and inverse checksum, then follows the data |
---|
23 | ;; area as a tagged array similar to BOOTP/DHCP, finally a tail |
---|
24 | ;; signature. |
---|
25 | ;; |
---|
26 | ;; Note that unlike BOOTP/DHCP, zero terminates the chain, and FF |
---|
27 | ;; has no special meaning. |
---|
28 | ;; |
---|
29 | |
---|
30 | ;; |
---|
31 | ;; List of ADV tags... |
---|
32 | ;; |
---|
33 | ADV_BOOTONCE equ 1 |
---|
34 | |
---|
35 | ;; |
---|
36 | ;; Other ADV data... |
---|
37 | ;; |
---|
38 | ADV_MAGIC1 equ 0x5a2d2fa5 ; Head signature |
---|
39 | ADV_MAGIC2 equ 0xa3041767 ; Total checksum |
---|
40 | ADV_MAGIC3 equ 0xdd28bf64 ; Tail signature |
---|
41 | |
---|
42 | ADV_LEN equ 500 ; Data bytes |
---|
43 | |
---|
44 | adv_retries equ 6 ; Disk retries |
---|
45 | |
---|
46 | section .data |
---|
47 | global __syslinux_adv_ptr, __syslinux_adv_size |
---|
48 | __syslinux_adv_ptr: |
---|
49 | dd adv0.data |
---|
50 | __syslinux_adv_size: |
---|
51 | dd ADV_LEN |
---|
52 | |
---|
53 | section .adv |
---|
54 | ; Introduce the ADVs to valid but blank |
---|
55 | adv0: |
---|
56 | .head resd 1 |
---|
57 | .csum resd 1 |
---|
58 | .data resb ADV_LEN |
---|
59 | .tail resd 1 |
---|
60 | .end equ $ |
---|
61 | adv1: |
---|
62 | .head resd 1 |
---|
63 | .csum resd 1 |
---|
64 | .data resb ADV_LEN |
---|
65 | .tail resd 1 |
---|
66 | .end equ $ |
---|
67 | section .text16 |
---|
68 | |
---|
69 | ; |
---|
70 | ; This is called after config file parsing, so we know |
---|
71 | ; the intended location of the ADV |
---|
72 | ; |
---|
73 | global adv_init |
---|
74 | adv_init: |
---|
75 | cmp byte [ADVDrive],-1 |
---|
76 | jne adv_read |
---|
77 | |
---|
78 | %if IS_SYSLINUX || IS_EXTLINUX |
---|
79 | cmp word [ADVSectors],2 ; Not present? |
---|
80 | jb adv_verify |
---|
81 | |
---|
82 | mov eax,[Hidden] |
---|
83 | mov edx,[Hidden+4] |
---|
84 | add [ADVSec0],eax |
---|
85 | adc [ADVSec0+4],edx |
---|
86 | add [ADVSec1],eax |
---|
87 | adc [ADVSec1+4],edx |
---|
88 | mov al,[DriveNumber] |
---|
89 | mov [ADVDrive],al |
---|
90 | jmp adv_read |
---|
91 | %endif |
---|
92 | |
---|
93 | ; |
---|
94 | ; Initialize the ADV data structure in memory |
---|
95 | ; |
---|
96 | adv_verify: |
---|
97 | cmp byte [ADVDrive],-1 ; No ADV configured, still? |
---|
98 | je .reset ; Then unconditionally reset |
---|
99 | |
---|
100 | mov si,adv0 |
---|
101 | call .check_adv |
---|
102 | jz .ok ; Primary ADV okay |
---|
103 | mov si,adv1 |
---|
104 | call .check_adv |
---|
105 | jz .adv1ok |
---|
106 | |
---|
107 | ; Neither ADV is usable; initialize to blank |
---|
108 | .reset: |
---|
109 | mov di,adv0 |
---|
110 | mov eax,ADV_MAGIC1 |
---|
111 | stosd |
---|
112 | mov eax,ADV_MAGIC2 |
---|
113 | stosd |
---|
114 | xor eax,eax |
---|
115 | mov cx,ADV_LEN/4 |
---|
116 | rep stosd |
---|
117 | mov eax,ADV_MAGIC3 |
---|
118 | stosd |
---|
119 | |
---|
120 | .ok: |
---|
121 | ret |
---|
122 | |
---|
123 | ; The primary ADV is bad, but the backup is OK |
---|
124 | .adv1ok: |
---|
125 | mov di,adv0 |
---|
126 | mov cx,512/4 |
---|
127 | rep movsd |
---|
128 | ret |
---|
129 | |
---|
130 | |
---|
131 | ; SI points to the putative ADV; unchanged by routine |
---|
132 | ; ZF=1 on return if good |
---|
133 | .check_adv: |
---|
134 | push si |
---|
135 | lodsd |
---|
136 | cmp eax,ADV_MAGIC1 |
---|
137 | jne .done ; ZF=0, i.e. bad |
---|
138 | xor edx,edx |
---|
139 | mov cx,ADV_LEN/4+1 ; Remaining dwords |
---|
140 | .csum: |
---|
141 | lodsd |
---|
142 | add edx,eax |
---|
143 | loop .csum |
---|
144 | cmp edx,ADV_MAGIC2 |
---|
145 | jne .done |
---|
146 | lodsd |
---|
147 | cmp eax,ADV_MAGIC3 |
---|
148 | .done: |
---|
149 | pop si |
---|
150 | ret |
---|
151 | |
---|
152 | ; |
---|
153 | ; adv_get: find an ADV string if present |
---|
154 | ; |
---|
155 | ; Input: DL = ADV ID |
---|
156 | ; Output: CX = byte count (zero on not found) |
---|
157 | ; SI = pointer to data |
---|
158 | ; DL = unchanged |
---|
159 | ; |
---|
160 | ; Assumes CS == DS. |
---|
161 | ; |
---|
162 | |
---|
163 | adv_get: |
---|
164 | push ax |
---|
165 | mov si,adv0.data |
---|
166 | xor ax,ax ; Keep AH=0 at all times |
---|
167 | .loop: |
---|
168 | lodsb ; Read ID |
---|
169 | cmp al,dl |
---|
170 | je .found |
---|
171 | and al,al |
---|
172 | jz .end |
---|
173 | lodsb ; Read length |
---|
174 | add si,ax |
---|
175 | cmp si,adv0.tail |
---|
176 | jb .loop |
---|
177 | jmp .end |
---|
178 | |
---|
179 | .found: |
---|
180 | lodsb |
---|
181 | mov cx,ax |
---|
182 | add ax,si ; Make sure it fits |
---|
183 | cmp ax,adv0.tail |
---|
184 | jbe .ok |
---|
185 | .end: |
---|
186 | xor cx,cx |
---|
187 | .ok: |
---|
188 | pop ax |
---|
189 | ret |
---|
190 | |
---|
191 | ; |
---|
192 | ; adv_set: insert a string into the ADV in memory |
---|
193 | ; |
---|
194 | ; Input: DL = ADV ID |
---|
195 | ; FS:BX = input buffer |
---|
196 | ; CX = byte count (max = 255!) |
---|
197 | ; Output: CF=1 on error |
---|
198 | ; CX clobbered |
---|
199 | ; |
---|
200 | ; Assumes CS == DS == ES. |
---|
201 | ; |
---|
202 | adv_set: |
---|
203 | push ax |
---|
204 | push si |
---|
205 | push di |
---|
206 | and ch,ch |
---|
207 | jnz .overflow |
---|
208 | |
---|
209 | push cx |
---|
210 | mov si,adv0.data |
---|
211 | xor ax,ax |
---|
212 | .loop: |
---|
213 | lodsb |
---|
214 | cmp al,dl |
---|
215 | je .found |
---|
216 | and al,al |
---|
217 | jz .endz |
---|
218 | lodsb |
---|
219 | add si,ax |
---|
220 | cmp si,adv0.tail |
---|
221 | jb .loop |
---|
222 | jmp .end |
---|
223 | |
---|
224 | .found: ; Found, need to delete old copy |
---|
225 | lodsb |
---|
226 | lea di,[si-2] |
---|
227 | push di |
---|
228 | add si,ax |
---|
229 | mov cx,adv0.tail |
---|
230 | sub cx,si |
---|
231 | jb .nukeit |
---|
232 | rep movsb ; Remove the old one |
---|
233 | mov [di],ah ; Termination zero |
---|
234 | pop si |
---|
235 | jmp .loop |
---|
236 | .nukeit: |
---|
237 | pop si |
---|
238 | jmp .end |
---|
239 | .endz: |
---|
240 | dec si |
---|
241 | .end: |
---|
242 | ; Now SI points to where we want to put our data |
---|
243 | pop cx |
---|
244 | mov di,si |
---|
245 | jcxz .empty |
---|
246 | add si,cx |
---|
247 | cmp si,adv0.tail-2 |
---|
248 | jae .overflow ; CF=0 |
---|
249 | |
---|
250 | mov si,bx |
---|
251 | mov al,dl |
---|
252 | stosb |
---|
253 | mov al,cl |
---|
254 | stosb |
---|
255 | fs rep movsb |
---|
256 | |
---|
257 | .empty: |
---|
258 | mov cx,adv0.tail |
---|
259 | sub cx,di |
---|
260 | xor ax,ax |
---|
261 | rep stosb ; Zero-fill remainder |
---|
262 | |
---|
263 | clc |
---|
264 | .done: |
---|
265 | pop di |
---|
266 | pop si |
---|
267 | pop ax |
---|
268 | ret |
---|
269 | .overflow: |
---|
270 | stc |
---|
271 | jmp .done |
---|
272 | |
---|
273 | ; |
---|
274 | ; adv_cleanup: checksum adv0 and copy to adv1 |
---|
275 | ; Assumes CS == DS == ES. |
---|
276 | ; |
---|
277 | adv_cleanup: |
---|
278 | pushad |
---|
279 | mov si,adv0.data |
---|
280 | mov cx,ADV_LEN/4 |
---|
281 | xor edx,edx |
---|
282 | .loop: |
---|
283 | lodsd |
---|
284 | add edx,eax |
---|
285 | loop .loop |
---|
286 | mov eax,ADV_MAGIC2 |
---|
287 | sub eax,edx |
---|
288 | lea di,[si+4] ; adv1 |
---|
289 | mov si,adv0 |
---|
290 | mov [si+4],eax ; Store checksum |
---|
291 | mov cx,(ADV_LEN+12)/4 |
---|
292 | rep movsd |
---|
293 | popad |
---|
294 | ret |
---|
295 | |
---|
296 | ; |
---|
297 | ; adv_write: write the ADV to disk. |
---|
298 | ; |
---|
299 | ; Location is in memory variables. |
---|
300 | ; Assumes CS == DS == ES. |
---|
301 | ; |
---|
302 | ; Returns CF=1 if the ADV cannot be written. |
---|
303 | ; |
---|
304 | global adv_write |
---|
305 | adv_write: |
---|
306 | push eax |
---|
307 | mov eax,[ADVSec0] |
---|
308 | or eax,[ADVSec0+4] |
---|
309 | je .bad |
---|
310 | mov eax,[ADVSec1] |
---|
311 | or eax,[ADVSec1+4] |
---|
312 | je .bad |
---|
313 | cmp byte [ADVDrive],-1 |
---|
314 | je .bad |
---|
315 | |
---|
316 | call adv_cleanup |
---|
317 | mov ah,3 ; Write |
---|
318 | call adv_read_write |
---|
319 | |
---|
320 | clc |
---|
321 | pop eax |
---|
322 | ret |
---|
323 | .bad: ; No location for ADV set |
---|
324 | stc |
---|
325 | pop eax |
---|
326 | ret |
---|
327 | |
---|
328 | ; |
---|
329 | ; adv_read: read the ADV from disk |
---|
330 | ; |
---|
331 | ; Location is in memory variables. |
---|
332 | ; Assumes CS == DS == ES. |
---|
333 | ; |
---|
334 | adv_read: |
---|
335 | push ax |
---|
336 | mov ah,2 ; Read |
---|
337 | call adv_read_write |
---|
338 | call adv_verify |
---|
339 | pop ax |
---|
340 | ret |
---|
341 | |
---|
342 | ; |
---|
343 | ; adv_read_write: disk I/O for the ADV |
---|
344 | ; |
---|
345 | ; On input, AH=2 for read, AH=3 for write. |
---|
346 | ; Assumes CS == DS == ES. |
---|
347 | ; |
---|
348 | adv_read_write: |
---|
349 | mov [ADVOp],ah |
---|
350 | pushad |
---|
351 | |
---|
352 | ; Check for EDD |
---|
353 | mov bx,55AAh |
---|
354 | mov ah,41h ; EDD existence query |
---|
355 | mov dl,[ADVDrive] |
---|
356 | int 13h |
---|
357 | mov si,.cbios |
---|
358 | jc .noedd |
---|
359 | cmp bx,0AA55h |
---|
360 | jne .noedd |
---|
361 | test cl,1 |
---|
362 | jz .noedd |
---|
363 | mov si,.ebios |
---|
364 | .noedd: |
---|
365 | |
---|
366 | mov eax,[ADVSec0] |
---|
367 | mov edx,[ADVSec0+4] |
---|
368 | mov bx,adv0 |
---|
369 | call .doone |
---|
370 | |
---|
371 | mov eax,[ADVSec1] |
---|
372 | mov edx,[ADVSec1+4] |
---|
373 | mov bx,adv1 |
---|
374 | call .doone |
---|
375 | |
---|
376 | popad |
---|
377 | ret |
---|
378 | |
---|
379 | .doone: |
---|
380 | push si |
---|
381 | jmp si |
---|
382 | |
---|
383 | .ebios: |
---|
384 | mov cx,adv_retries |
---|
385 | .eb_retry: |
---|
386 | ; Form DAPA on stack |
---|
387 | push edx |
---|
388 | push eax |
---|
389 | push es |
---|
390 | push bx |
---|
391 | push word 1 ; Sector count |
---|
392 | push word 16 ; DAPA size |
---|
393 | mov si,sp |
---|
394 | pushad |
---|
395 | mov dl,[ADVDrive] |
---|
396 | mov ax,4000h |
---|
397 | or ah,[ADVOp] |
---|
398 | push ds |
---|
399 | push ss |
---|
400 | pop ds |
---|
401 | int 13h |
---|
402 | pop ds |
---|
403 | popad |
---|
404 | lea sp,[si+16] ; Remove DAPA |
---|
405 | jc .eb_error |
---|
406 | pop si |
---|
407 | ret |
---|
408 | .eb_error: |
---|
409 | loop .eb_retry |
---|
410 | stc |
---|
411 | pop si |
---|
412 | ret |
---|
413 | |
---|
414 | .cbios: |
---|
415 | push edx |
---|
416 | push eax |
---|
417 | push bp |
---|
418 | |
---|
419 | and edx,edx ; > 2 TiB not possible |
---|
420 | jnz .cb_overflow |
---|
421 | |
---|
422 | mov dl,[ADVDrive] |
---|
423 | and dl,dl |
---|
424 | ; Floppies: can't trust INT 13h 08h, we better know |
---|
425 | ; the geometry a priori, which means it better be our |
---|
426 | ; boot device... |
---|
427 | jns .noparm ; Floppy drive... urk |
---|
428 | |
---|
429 | mov ah,08h ; Get disk parameters |
---|
430 | int 13h |
---|
431 | jc .noparm |
---|
432 | and ah,ah |
---|
433 | jnz .noparm |
---|
434 | shr dx,8 |
---|
435 | inc dx |
---|
436 | movzx edi,dx ; EDI = heads |
---|
437 | and cx,3fh |
---|
438 | movzx esi,cx ; ESI = sectors/track |
---|
439 | jmp .parmok |
---|
440 | |
---|
441 | .noparm: |
---|
442 | ; No CHS info... this better be our boot drive, then |
---|
443 | %if IS_SYSLINUX || IS_EXTLINUX |
---|
444 | cmp dl,[DriveNumber] |
---|
445 | jne .cb_overflow ; Fatal error! |
---|
446 | movzx esi,word [bsSecPerTrack] |
---|
447 | movzx edi,word [bsHeads] |
---|
448 | %else |
---|
449 | ; Not a disk-based derivative... there is no hope |
---|
450 | jmp .cb_overflow |
---|
451 | %endif |
---|
452 | |
---|
453 | .parmok: |
---|
454 | ; |
---|
455 | ; Dividing by sectors to get (track,sector): we may have |
---|
456 | ; up to 2^18 tracks, so we need to use 32-bit arithmetric. |
---|
457 | ; |
---|
458 | xor edx,edx |
---|
459 | div esi |
---|
460 | xor cx,cx |
---|
461 | xchg cx,dx ; CX <- sector index (0-based) |
---|
462 | ; EDX <- 0 |
---|
463 | ; eax = track # |
---|
464 | div edi ; Convert track to head/cyl |
---|
465 | |
---|
466 | ; Watch out for overflow, we might be writing! |
---|
467 | cmp eax,1023 |
---|
468 | ja .cb_overflow |
---|
469 | |
---|
470 | ; |
---|
471 | ; Now we have AX = cyl, DX = head, CX = sector (0-based), |
---|
472 | ; BP = sectors to transfer, SI = bsSecPerTrack, |
---|
473 | ; ES:BX = data target |
---|
474 | ; |
---|
475 | |
---|
476 | shl ah,6 ; Because IBM was STOOPID |
---|
477 | ; and thought 8 bits were enough |
---|
478 | ; then thought 10 bits were enough... |
---|
479 | inc cx ; Sector numbers are 1-based, sigh |
---|
480 | or cl,ah |
---|
481 | mov ch,al |
---|
482 | mov dh,dl |
---|
483 | mov dl,[ADVDrive] |
---|
484 | mov al,01h ; Transfer one sector |
---|
485 | mov ah,[ADVOp] ; Operation |
---|
486 | |
---|
487 | mov bp,adv_retries |
---|
488 | .cb_retry: |
---|
489 | pushad |
---|
490 | int 13h |
---|
491 | popad |
---|
492 | jc .cb_error |
---|
493 | |
---|
494 | .cb_done: |
---|
495 | pop bp |
---|
496 | pop eax |
---|
497 | pop edx |
---|
498 | pop si |
---|
499 | ret |
---|
500 | |
---|
501 | .cb_error: |
---|
502 | dec bp |
---|
503 | jnz .cb_retry |
---|
504 | .cb_overflow: |
---|
505 | stc |
---|
506 | jmp .cb_done |
---|
507 | |
---|
508 | section .data16 |
---|
509 | alignz 8 |
---|
510 | ADVSec0 dq 0 ; Not specified |
---|
511 | ADVSec1 dq 0 ; Not specified |
---|
512 | ADVDrive db -1 ; No ADV defined |
---|
513 | ADVCHSInfo db -1 ; We have CHS info for this drive |
---|
514 | |
---|
515 | section .bss16 |
---|
516 | ADVOp resb 1 |
---|
517 | |
---|
518 | section .text16 |
---|