Merge remote branch 'marcel/luaext'
[profile/ivi/syslinux.git] / core / adv.inc
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 .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            equ $
54 adv1:
55 .head           resd 1
56 .csum           resd 1
57 .data           resb ADV_LEN
58 .tail           resd 1
59 .end            equ $
60                 section .text16
61
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
69
70 %if IS_SYSLINUX || IS_EXTLINUX
71                 cmp word [ADVSectors],2         ; Not present?
72                 jb adv_verify
73
74                 mov eax,[Hidden]
75                 mov edx,[Hidden+4]
76                 add [ADVSec0],eax
77                 adc [ADVSec0+4],edx
78                 add [ADVSec1],eax
79                 adc [ADVSec1+4],edx
80                 mov al,[DriveNumber]
81                 mov [ADVDrive],al
82                 jmp adv_read
83 %endif
84
85                 ;
86                 ; Initialize the ADV data structure in memory
87                 ;
88 adv_verify:
89                 cmp byte [ADVDrive],-1          ; No ADV configured, still?
90                 je .reset                       ; Then unconditionally reset
91
92                 mov si,adv0
93                 call .check_adv
94                 jz .ok                          ; Primary ADV okay
95                 mov si,adv1
96                 call .check_adv
97                 jz .adv1ok
98
99                 ; Neither ADV is usable; initialize to blank
100 .reset:
101                 mov di,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
111
112 .ok:
113                 ret
114
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
121
122
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
143
144 ;
145 ; adv_get: find an ADV string if present
146 ;
147 ; Input:        DL      = ADV ID
148 ; Output:       CX      = byte count (zero on not found)
149 ;               SI      = pointer to data
150 ;               DL      = unchanged
151 ;
152 ; Assumes CS == DS.
153 ;
154
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
170
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
182
183 ;
184 ; adv_set: insert a string into the ADV in memory
185 ;
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
191 ;
192 ; Assumes CS == DS == ES.
193 ;
194 adv_set:
195                 push ax
196                 push si
197                 push di
198                 and ch,ch
199                 jnz .overflow
200
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
215
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
241
242                 mov si,bx
243                 mov al,dl
244                 stosb
245                 mov al,cl
246                 stosb
247                 fs rep movsb
248
249 .empty:
250                 mov cx,adv0.tail
251                 sub cx,di
252                 xor ax,ax
253                 rep stosb                       ; Zero-fill remainder
254
255                 clc
256 .done:
257                 pop di
258                 pop si
259                 pop ax
260                 ret
261 .overflow:
262                 stc
263                 jmp .done
264
265 ;
266 ; adv_cleanup:  checksum adv0 and copy to adv1
267 ;               Assumes CS == DS == ES.
268 ;
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
287
288 ;
289 ; adv_write:    write the ADV to disk.
290 ;
291 ;               Location is in memory variables.
292 ;               Assumes CS == DS == ES.
293 ;
294 ;               Returns CF=1 if the ADV cannot be written.
295 ;
296 adv_write:
297                 push eax
298                 mov eax,[ADVSec0]
299                 or eax,[ADVSec0+4]
300                 je .bad
301                 mov eax,[ADVSec1]
302                 or eax,[ADVSec1+4]
303                 je .bad
304                 cmp byte [ADVDrive],-1
305                 je .bad
306
307                 call adv_cleanup
308                 mov ah,3                        ; Write
309                 call adv_read_write
310
311                 clc
312                 pop eax
313                 ret
314 .bad:                                           ; No location for ADV set
315                 stc
316                 pop eax
317                 ret
318
319 ;
320 ; adv_read:     read the ADV from disk
321 ;
322 ;               Location is in memory variables.
323 ;               Assumes CS == DS == ES.
324 ;
325 adv_read:
326                 push ax
327                 mov ah,2                        ; Read
328                 call adv_read_write
329                 call adv_verify
330                 pop ax
331                 ret
332
333 ;
334 ; adv_read_write: disk I/O for the ADV
335 ;
336 ;               On input, AH=2 for read, AH=3 for write.
337 ;               Assumes CS == DS == ES.
338 ;
339 adv_read_write:
340                 mov [ADVOp],ah
341                 pushad
342
343                 ; Check for EDD
344                 mov bx,55AAh
345                 mov ah,41h                      ; EDD existence query
346                 mov dl,[ADVDrive]
347                 int 13h
348                 mov si,.cbios
349                 jc .noedd
350                 cmp bx,0AA55h
351                 jne .noedd
352                 test cl,1
353                 jz .noedd
354                 mov si,.ebios
355 .noedd:
356
357                 mov eax,[ADVSec0]
358                 mov edx,[ADVSec0+4]
359                 mov bx,adv0
360                 call .doone
361
362                 mov eax,[ADVSec1]
363                 mov edx,[ADVSec1+4]
364                 mov bx,adv1
365                 call .doone
366
367                 popad
368                 ret
369
370 .doone:
371                 push si
372                 jmp si
373
374 .ebios:
375                 mov cx,adv_retries
376 .eb_retry:
377                 ; Form DAPA on stack
378                 push edx
379                 push eax
380                 push es
381                 push bx
382                 push word 1                     ; Sector count
383                 push word 16                    ; DAPA size
384                 mov si,sp
385                 pushad
386                 mov dl,[ADVDrive]
387                 mov ax,4000h
388                 or ah,[ADVOp]
389                 push ds
390                 push ss
391                 pop ds
392                 int 13h
393                 pop ds
394                 popad
395                 lea sp,[si+16]                  ; Remove DAPA
396                 jc .eb_error
397                 pop si
398                 ret
399 .eb_error:
400                 loop .eb_retry
401                 stc
402                 pop si
403                 ret
404
405 .cbios:
406                 push edx
407                 push eax
408                 push bp
409
410                 and edx,edx                     ; > 2 TiB not possible
411                 jnz .cb_overflow
412
413                 mov dl,[ADVDrive]
414                 and dl,dl
415                 ; Floppies: can't trust INT 13h 08h, we better know
416                 ; the geometry a priori, which means it better be our
417                 ; boot device...
418                 jns .noparm                     ; Floppy drive... urk
419
420                 mov ah,08h                      ; Get disk parameters
421                 int 13h
422                 jc .noparm
423                 and ah,ah
424                 jnz .noparm
425                 shr dx,8
426                 inc dx
427                 movzx edi,dx                    ; EDI = heads
428                 and cx,3fh
429                 movzx esi,cx                    ; ESI = sectors/track
430                 jmp .parmok
431
432 .noparm:
433                 ; No CHS info... this better be our boot drive, then
434 %if IS_SYSLINUX || IS_EXTLINUX
435                 cmp dl,[DriveNumber]
436                 jne .cb_overflow                ; Fatal error!
437                 movzx esi,word [bsSecPerTrack]
438                 movzx edi,word [bsHeads]
439 %else
440                 ; Not a disk-based derivative... there is no hope
441                 jmp .cb_overflow
442 %endif
443
444 .parmok:
445                 ;
446                 ; Dividing by sectors to get (track,sector): we may have
447                 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
448                 ;
449                 xor edx,edx
450                 div esi
451                 xor cx,cx
452                 xchg cx,dx              ; CX <- sector index (0-based)
453                                         ; EDX <- 0
454                 ; eax = track #
455                 div edi                 ; Convert track to head/cyl
456
457                 ; Watch out for overflow, we might be writing!
458                 cmp eax,1023
459                 ja .cb_overflow
460
461                 ;
462                 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
463                 ; BP = sectors to transfer, SI = bsSecPerTrack,
464                 ; ES:BX = data target
465                 ;
466
467                 shl ah,6                ; Because IBM was STOOPID
468                                         ; and thought 8 bits were enough
469                                         ; then thought 10 bits were enough...
470                 inc cx                  ; Sector numbers are 1-based, sigh
471                 or cl,ah
472                 mov ch,al
473                 mov dh,dl
474                 mov dl,[ADVDrive]
475                 mov al,01h              ; Transfer one sector
476                 mov ah,[ADVOp]          ; Operation
477
478                 mov bp,adv_retries
479 .cb_retry:
480                 pushad
481                 int 13h
482                 popad
483                 jc .cb_error
484
485 .cb_done:
486                 pop bp
487                 pop eax
488                 pop edx
489                 pop si
490                 ret
491
492 .cb_error:
493                 dec bp
494                 jnz .cb_retry
495 .cb_overflow:
496                 stc
497                 jmp .cb_done
498
499                 section .data16
500                 alignz 8
501 ADVSec0         dq 0                    ; Not specified
502 ADVSec1         dq 0                    ; Not specified
503 ADVDrive        db -1                   ; No ADV defined
504 ADVCHSInfo      db -1                   ; We have CHS info for this drive
505
506                 section .bss16
507 ADVOp           resb 1
508
509                 section .text16