Higher confidence in the harmlessness of the ADV code
[syslinux.git] / adv.inc
blob7eca4b5658d4730aeb96288ef4d3ed333d18b4d2
1 ;; -----------------------------------------------------------------------
2 ;;
3 ;;   Copyright 2007 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., 53 Temple Place Ste 330,
8 ;;   Boston MA 02111-1307, USA; either version 2 of the License, or
9 ;;   (at your option) any later version; incorporated herein by reference.
11 ;; -----------------------------------------------------------------------
14 ;; adv.inc
16 ;; The auxillary data vector and its routines
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.
26 ;; Note that unlike BOOTP/DHCP, zero terminates the chain, and FF
27 ;; has no special meaning.
31 ;; List of ADV tags...
33 ADV_BOOTONCE    equ 1
36 ;; Other ADV data...
38 ADV_MAGIC1      equ 0x5a2d2fa5                  ; Head signature
39 ADV_MAGIC2      equ 0xa3041767                  ; Total checksum
40 ADV_MAGIC3      equ 0xdd28bf64                  ; Tail signature
42 ADV_LEN         equ 500                         ; Data bytes
44 adv_retries     equ 6                           ; Disk retries
46                 section .adv
47                 ; Introduce the ADVs to valid but blank
48 adv0:
49 .head           resd 1
50 .csum           resd 1
51 .data           resb ADV_LEN
52 .tail           resd 1
53 .end
54 adv1:
55 .head           resd 1
56 .csum           resd 1
57 .data           resb ADV_LEN
58 .tail           resd 1
59 .end
60                 section .text
62                 ;
63                 ; This is called after config file parsing, so we know
64                 ; the intended location of the ADV
65                 ;
66 adv_init:
67                 cmp byte [ADVDrive],-1
68                 jne adv_read
70 ;%if IS_SYSLINUX || IS_MDSLINUX || IS_EXTLINUX
71 %if IS_EXTLINUX         ; Not yet implemented for the other derivatives
72                 ;
73                 ; Update pointers to default ADVs...
74                 ;
75                 mov bx,[LDLSectors]
76                 shl bx,2
77                 mov ecx,[bsHidden]
78                 mov eax,[bx+SectorPtrs-8]
79                 mov edx,[bx+SectorPtrs-4]
80                 add eax,ecx
81                 add edx,ecx
82                 mov [ADVSec0],eax
83                 mov [ADVSec1],edx
84                 mov al,[DriveNumber]
85                 mov [ADVDrive],al
86 %endif
87                 ; ** fall through to adv_verify **
89                 ;
90                 ; Initialize the ADV data structure in memory
91                 ;
92 adv_verify:
93                 mov si,adv0
94                 call .check_adv
95                 jz .ok                          ; Primary ADV okay
96                 mov si,adv1
97                 call .check_adv
98                 jz .adv1ok
100                 ; Neither ADV is usable; initialize to blank
101                 mov si,adv0
102                 mov eax,ADV_MAGIC1
103                 stosd
104                 mov eax,ADV_MAGIC2
105                 stosd
106                 xor eax,eax
107                 mov cx,ADV_LEN/4
108                 rep stosd
109                 mov eax,ADV_MAGIC3
110                 stosd
112 .ok:
113                 ret
115                 ; The primary ADV is bad, but the backup is OK
116 .adv1ok:
117                 mov di,adv0
118                 mov cx,512/4
119                 rep movsd
120                 ret
123                 ; SI points to the putative ADV; unchanged by routine
124                 ; ZF=1 on return if good
125 .check_adv:
126                 push si
127                 lodsd
128                 cmp eax,ADV_MAGIC1
129                 jne .done                       ; ZF=0, i.e. bad
130                 xor edx,edx
131                 mov cx,ADV_LEN/4+1              ; Remaining dwords
132 .csum:
133                 lodsd
134                 add edx,eax
135                 loop .csum
136                 cmp edx,ADV_MAGIC2
137                 jne .done
138                 lodsd
139                 cmp eax,ADV_MAGIC3
140 .done:
141                 pop si
142                 ret
145 ; adv_get: find an ADV string if present
147 ; Input:        DL      = ADV ID
148 ; Output:       CX      = byte count (zero on not found)
149 ;               SI      = pointer to data
150 ;               DL      = unchanged
152 ; Assumes CS == DS.
155 adv_get:
156                 push ax
157                 mov si,adv0.data
158                 xor ax,ax                       ; Keep AH=0 at all times
159 .loop:
160                 lodsb                           ; Read ID
161                 cmp al,dl
162                 je .found
163                 and al,al
164                 jz .end
165                 lodsb                           ; Read length
166                 add si,ax
167                 cmp si,adv0.tail
168                 jb .loop
169                 jmp .end
171 .found:
172                 lodsb
173                 mov cx,ax
174                 add ax,si                       ; Make sure it fits
175                 cmp ax,adv0.tail
176                 jbe .ok
177 .end:
178                 xor cx,cx
179 .ok:
180                 pop ax
181                 ret
184 ; adv_set: insert a string into the ADV in memory
186 ; Input:        DL      = ADV ID
187 ;               FS:BX   = input buffer
188 ;               CX      = byte count (max = 255!)
189 ; Output:       CF=1 on error
190 ;               CX      clobbered
192 ; Assumes CS == DS == ES.
194 adv_set:
195                 push ax
196                 push si
197                 push di
198                 and ch,ch
199                 jnz .overflow
201                 push cx
202                 mov si,adv0.data
203                 xor ax,ax
204 .loop:
205                 lodsb
206                 cmp al,dl
207                 je .found
208                 and al,al
209                 jz .endz
210                 lodsb
211                 add si,ax
212                 cmp si,adv0.tail
213                 jb .loop
214                 jmp .end
216 .found:         ; Found, need to delete old copy
217                 lodsb
218                 lea di,[si-2]
219                 push di
220                 add si,ax
221                 mov cx,adv0.tail
222                 sub cx,si
223                 jb .nukeit
224                 rep movsb                       ; Remove the old one
225                 mov [di],ah                     ; Termination zero
226                 pop si
227                 jmp .loop
228 .nukeit:
229                 pop si
230                 jmp .end
231 .endz:
232                 dec si
233 .end:
234                 ; Now SI points to where we want to put our data
235                 pop cx
236                 mov di,si
237                 jcxz .empty
238                 add si,cx
239                 cmp si,adv0.tail-2
240                 jae .overflow                   ; CF=0
242                 mov si,bx
243                 mov al,dl
244                 stosb
245                 mov al,cl
246                 stosb
247                 fs rep movsb
249 .empty:
250                 mov cx,adv0.tail
251                 sub cx,di
252                 xor ax,ax
253                 rep stosb                       ; Zero-fill remainder
255                 clc
256 .done:
257                 pop di
258                 pop si
259                 pop ax
260                 ret
261 .overflow:
262                 stc
263                 jmp .done
266 ; adv_cleanup:  checksum adv0 and copy to adv1
267 ;               Assumes CS == DS == ES.
269 adv_cleanup:
270                 pushad
271                 mov si,adv0.data
272                 mov cx,ADV_LEN/4
273                 xor edx,edx
274 .loop:
275                 lodsd
276                 add edx,eax
277                 loop .loop
278                 mov eax,ADV_MAGIC2
279                 sub eax,edx
280                 lea di,[si+4]                   ; adv1
281                 mov si,adv0
282                 mov [si+4],eax                  ; Store checksum
283                 mov cx,(ADV_LEN+12)/4
284                 rep movsd
285                 popad
286                 ret
289 ; adv_write:    write the ADV to disk.
291 ;               Location is in memory variables.
292 ;               Assumes CS == DS == ES.
294 ;               Returns CF=1 if the ADV cannot be written.
296 adv_write:
297                 cmp dword [ADVSec0],0
298                 je .bad
299                 cmp dword [ADVSec1],0
300                 je .bad
301                 cmp byte [ADVDrive],-1
302                 je .bad
304                 push ax
305                 call adv_cleanup
306                 mov ah,3                        ; Write
307                 call adv_read_write
308                 pop ax
310                 clc
311                 ret
312 .bad:                                           ; No location for ADV set
313                 stc
314                 ret
317 ; adv_read:     read the ADV from disk
319 ;               Location is in memory variables.
320 ;               Assumes CS == DS == ES.
322 adv_read:
323                 push ax
324                 mov ah,2                        ; Read
325                 call adv_read_write
326                 call adv_verify
327                 pop ax
328                 ret
331 ; adv_read_write: disk I/O for the ADV
333 ;               On input, AH=2 for read, AH=3 for write.
334 ;               Assumes CS == DS == ES.
336 adv_read_write:
337                 mov [ADVOp],ah
338                 pushad
340                 mov dl,[ADVDrive]
341                 and dl,dl
342                 ; Floppies: can't trust INT 13h 08h, we better know
343                 ; the geometry a priori, which means it better be our
344                 ; boot device.  Handle that later.
345                 ; jns .floppy                   ; Floppy drive... urk
347                 mov ah,08h                      ; Get disk parameters
348                 int 13h
349                 jc .noparm
350                 and ah,ah
351                 jnz .noparm
352                 shr dx,8
353                 inc dx
354                 mov [ADVHeads],dx
355                 and cx,3fh
356                 mov [ADVSecPerTrack],cx
358 .noparm:
359                 ; Check for EDD
360                 mov bx,55AAh
361                 mov ah,41h                      ; EDD existence query
362                 mov dl,[ADVDrive]
363                 int 13h
364                 mov si,.cbios
365                 jc .noedd
366                 mov si,.ebios
367 .noedd:
369                 mov eax,[ADVSec0]
370                 mov bx,adv0
371                 call .doone
373                 mov eax,[ADVSec1]
374                 mov bx,adv1
375                 call .doone
377                 popad
378                 ret
380 .doone:
381                 xor edx,edx                     ; Zero-extend LBA
382                 push si
383                 jmp si
385 .ebios:
386                 mov cx,adv_retries
387 .eb_retry:
388                 ; Form DAPA on stack
389                 push edx
390                 push eax
391                 push es
392                 push bx
393                 push word 1                     ; Sector count
394                 push word 16                    ; DAPA size
395                 mov si,sp
396                 pushad
397                 mov dl,[ADVDrive]
398                 mov ax,4080h
399                 or ah,[ADVOp]
400                 push ds
401                 push ss
402                 pop ds
403                 int 13h
404                 pop ds
405                 popad
406                 lea sp,[si+16]                  ; Remove DAPA
407                 jc .eb_error
408                 pop si
409                 ret
410 .eb_error:
411                 loop .eb_retry
412                 stc
413                 pop si
414                 ret
416 .cbios:
417                 push edx
418                 push eax
419                 push bp
421                 movzx esi,word [ADVSecPerTrack]
422                 movzx edi,word [ADVHeads]
423                 ;
424                 ; Dividing by sectors to get (track,sector): we may have
425                 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
426                 ;
427                 div esi
428                 xor cx,cx
429                 xchg cx,dx              ; CX <- sector index (0-based)
430                                         ; EDX <- 0
431                 ; eax = track #
432                 div edi                 ; Convert track to head/cyl
434                 ; Watch out for overflow, we might be writing!
435                 cmp eax,1023
436                 ja .cb_overflow
438                 ;
439                 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
440                 ; BP = sectors to transfer, SI = bsSecPerTrack,
441                 ; ES:BX = data target
442                 ;
444                 shl ah,6                ; Because IBM was STOOPID
445                                         ; and thought 8 bits were enough
446                                         ; then thought 10 bits were enough...
447                 inc cx                  ; Sector numbers are 1-based, sigh
448                 or cl,ah
449                 mov ch,al
450                 mov dh,dl
451                 mov dl,[ADVDrive]
452                 xchg ax,bp              ; Sector to transfer count
453                 mov ah,[ADVOp]          ; Operation
455                 mov bp,adv_retries
456 .cb_retry:
457                 pushad
458                 int 13h
459                 popad
460                 jc .cb_error
462 .cb_done:
463                 pop bp
464                 pop eax
465                 pop edx
466                 ret
468 .cb_error:
469                 dec bp
470                 jnz .cb_retry
471 .cb_overflow:
472                 stc
473                 jmp .cb_done
475                 section .data
476                 align 4, db 0
477 ADVSec0         db 0                    ; Undefined
478 ADVSec1         db 0                    ; Undefined
479 ADVDrive        db -1                   ; No ADV defined
481                 section .bss
482                 alignb 4
483 ADVSecPerTrack  resw 1
484 ADVHeads        resw 1
485 ADVOp           resb 1