Support LOCALBOOT (ISOLINUX-style) in SYSLINUX/EXTLINUX
[syslinux.git] / adv.inc
blobc5e8270c8aaa46d76053e2ca21ceefcf22010e77
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.
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            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 .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                 cmp byte [ADVDrive],-1          ; No ADV configured, still?
94                 je .reset                       ; Then unconditionally reset
96                 mov si,adv0
97                 call .check_adv
98                 jz .ok                          ; Primary ADV okay
99                 mov si,adv1
100                 call .check_adv
101                 jz .adv1ok
103                 ; Neither ADV is usable; initialize to blank
104 .reset:
105                 mov di,adv0
106                 mov eax,ADV_MAGIC1
107                 stosd
108                 mov eax,ADV_MAGIC2
109                 stosd
110                 xor eax,eax
111                 mov cx,ADV_LEN/4
112                 rep stosd
113                 mov eax,ADV_MAGIC3
114                 stosd
116 .ok:
117                 ret
119                 ; The primary ADV is bad, but the backup is OK
120 .adv1ok:
121                 mov di,adv0
122                 mov cx,512/4
123                 rep movsd
124                 ret
127                 ; SI points to the putative ADV; unchanged by routine
128                 ; ZF=1 on return if good
129 .check_adv:
130                 push si
131                 lodsd
132                 cmp eax,ADV_MAGIC1
133                 jne .done                       ; ZF=0, i.e. bad
134                 xor edx,edx
135                 mov cx,ADV_LEN/4+1              ; Remaining dwords
136 .csum:
137                 lodsd
138                 add edx,eax
139                 loop .csum
140                 cmp edx,ADV_MAGIC2
141                 jne .done
142                 lodsd
143                 cmp eax,ADV_MAGIC3
144 .done:
145                 pop si
146                 ret
149 ; adv_get: find an ADV string if present
151 ; Input:        DL      = ADV ID
152 ; Output:       CX      = byte count (zero on not found)
153 ;               SI      = pointer to data
154 ;               DL      = unchanged
156 ; Assumes CS == DS.
159 adv_get:
160                 push ax
161                 mov si,adv0.data
162                 xor ax,ax                       ; Keep AH=0 at all times
163 .loop:
164                 lodsb                           ; Read ID
165                 cmp al,dl
166                 je .found
167                 and al,al
168                 jz .end
169                 lodsb                           ; Read length
170                 add si,ax
171                 cmp si,adv0.tail
172                 jb .loop
173                 jmp .end
175 .found:
176                 lodsb
177                 mov cx,ax
178                 add ax,si                       ; Make sure it fits
179                 cmp ax,adv0.tail
180                 jbe .ok
181 .end:
182                 xor cx,cx
183 .ok:
184                 pop ax
185                 ret
188 ; adv_set: insert a string into the ADV in memory
190 ; Input:        DL      = ADV ID
191 ;               FS:BX   = input buffer
192 ;               CX      = byte count (max = 255!)
193 ; Output:       CF=1 on error
194 ;               CX      clobbered
196 ; Assumes CS == DS == ES.
198 adv_set:
199                 push ax
200                 push si
201                 push di
202                 and ch,ch
203                 jnz .overflow
205                 push cx
206                 mov si,adv0.data
207                 xor ax,ax
208 .loop:
209                 lodsb
210                 cmp al,dl
211                 je .found
212                 and al,al
213                 jz .endz
214                 lodsb
215                 add si,ax
216                 cmp si,adv0.tail
217                 jb .loop
218                 jmp .end
220 .found:         ; Found, need to delete old copy
221                 lodsb
222                 lea di,[si-2]
223                 push di
224                 add si,ax
225                 mov cx,adv0.tail
226                 sub cx,si
227                 jb .nukeit
228                 rep movsb                       ; Remove the old one
229                 mov [di],ah                     ; Termination zero
230                 pop si
231                 jmp .loop
232 .nukeit:
233                 pop si
234                 jmp .end
235 .endz:
236                 dec si
237 .end:
238                 ; Now SI points to where we want to put our data
239                 pop cx
240                 mov di,si
241                 jcxz .empty
242                 add si,cx
243                 cmp si,adv0.tail-2
244                 jae .overflow                   ; CF=0
246                 mov si,bx
247                 mov al,dl
248                 stosb
249                 mov al,cl
250                 stosb
251                 fs rep movsb
253 .empty:
254                 mov cx,adv0.tail
255                 sub cx,di
256                 xor ax,ax
257                 rep stosb                       ; Zero-fill remainder
259                 clc
260 .done:
261                 pop di
262                 pop si
263                 pop ax
264                 ret
265 .overflow:
266                 stc
267                 jmp .done
270 ; adv_cleanup:  checksum adv0 and copy to adv1
271 ;               Assumes CS == DS == ES.
273 adv_cleanup:
274                 pushad
275                 mov si,adv0.data
276                 mov cx,ADV_LEN/4
277                 xor edx,edx
278 .loop:
279                 lodsd
280                 add edx,eax
281                 loop .loop
282                 mov eax,ADV_MAGIC2
283                 sub eax,edx
284                 lea di,[si+4]                   ; adv1
285                 mov si,adv0
286                 mov [si+4],eax                  ; Store checksum
287                 mov cx,(ADV_LEN+12)/4
288                 rep movsd
289                 popad
290                 ret
293 ; adv_write:    write the ADV to disk.
295 ;               Location is in memory variables.
296 ;               Assumes CS == DS == ES.
298 ;               Returns CF=1 if the ADV cannot be written.
300 adv_write:
301                 cmp dword [ADVSec0],0
302                 je .bad
303                 cmp dword [ADVSec1],0
304                 je .bad
305                 cmp byte [ADVDrive],-1
306                 je .bad
308                 push ax
309                 call adv_cleanup
310                 mov ah,3                        ; Write
311                 call adv_read_write
312                 pop ax
314                 clc
315                 ret
316 .bad:                                           ; No location for ADV set
317                 stc
318                 ret
321 ; adv_read:     read the ADV from disk
323 ;               Location is in memory variables.
324 ;               Assumes CS == DS == ES.
326 adv_read:
327                 push ax
328                 mov ah,2                        ; Read
329                 call adv_read_write
330                 call adv_verify
331                 pop ax
332                 ret
335 ; adv_read_write: disk I/O for the ADV
337 ;               On input, AH=2 for read, AH=3 for write.
338 ;               Assumes CS == DS == ES.
340 adv_read_write:
341                 mov [ADVOp],ah
342                 pushad
344                 mov dl,[ADVDrive]
345                 and dl,dl
346                 ; Floppies: can't trust INT 13h 08h, we better know
347                 ; the geometry a priori, which means it better be our
348                 ; boot device.  Handle that later.
349                 ; jns .floppy                   ; Floppy drive... urk
351                 mov ah,08h                      ; Get disk parameters
352                 int 13h
353                 jc .noparm
354                 and ah,ah
355                 jnz .noparm
356                 shr dx,8
357                 inc dx
358                 mov [ADVHeads],dx
359                 and cx,3fh
360                 mov [ADVSecPerTrack],cx
362 .noparm:
363                 ; Check for EDD
364                 mov bx,55AAh
365                 mov ah,41h                      ; EDD existence query
366                 mov dl,[ADVDrive]
367                 int 13h
368                 mov si,.cbios
369                 jc .noedd
370                 mov si,.ebios
371 .noedd:
373                 mov eax,[ADVSec0]
374                 mov bx,adv0
375                 call .doone
377                 mov eax,[ADVSec1]
378                 mov bx,adv1
379                 call .doone
381                 popad
382                 ret
384 .doone:
385                 xor edx,edx                     ; Zero-extend LBA
386                 push si
387                 jmp si
389 .ebios:
390                 mov cx,adv_retries
391 .eb_retry:
392                 ; Form DAPA on stack
393                 push edx
394                 push eax
395                 push es
396                 push bx
397                 push word 1                     ; Sector count
398                 push word 16                    ; DAPA size
399                 mov si,sp
400                 pushad
401                 mov dl,[ADVDrive]
402                 mov ax,4080h
403                 or ah,[ADVOp]
404                 push ds
405                 push ss
406                 pop ds
407                 int 13h
408                 pop ds
409                 popad
410                 lea sp,[si+16]                  ; Remove DAPA
411                 jc .eb_error
412                 pop si
413                 ret
414 .eb_error:
415                 loop .eb_retry
416                 stc
417                 pop si
418                 ret
420 .cbios:
421                 push edx
422                 push eax
423                 push bp
425                 movzx esi,word [ADVSecPerTrack]
426                 movzx edi,word [ADVHeads]
427                 ;
428                 ; Dividing by sectors to get (track,sector): we may have
429                 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
430                 ;
431                 div esi
432                 xor cx,cx
433                 xchg cx,dx              ; CX <- sector index (0-based)
434                                         ; EDX <- 0
435                 ; eax = track #
436                 div edi                 ; Convert track to head/cyl
438                 ; Watch out for overflow, we might be writing!
439                 cmp eax,1023
440                 ja .cb_overflow
442                 ;
443                 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
444                 ; BP = sectors to transfer, SI = bsSecPerTrack,
445                 ; ES:BX = data target
446                 ;
448                 shl ah,6                ; Because IBM was STOOPID
449                                         ; and thought 8 bits were enough
450                                         ; then thought 10 bits were enough...
451                 inc cx                  ; Sector numbers are 1-based, sigh
452                 or cl,ah
453                 mov ch,al
454                 mov dh,dl
455                 mov dl,[ADVDrive]
456                 xchg ax,bp              ; Sector to transfer count
457                 mov ah,[ADVOp]          ; Operation
459                 mov bp,adv_retries
460 .cb_retry:
461                 pushad
462                 int 13h
463                 popad
464                 jc .cb_error
466 .cb_done:
467                 pop bp
468                 pop eax
469                 pop edx
470                 ret
472 .cb_error:
473                 dec bp
474                 jnz .cb_retry
475 .cb_overflow:
476                 stc
477                 jmp .cb_done
479                 section .data
480                 align 4, db 0
481 ADVSec0         dd 0                    ; Not specified
482 ADVSec1         dd 0                    ; Not specified
483 ADVDrive        db -1                   ; No ADV defined
485                 section .bss
486                 alignb 4
487 ADVSecPerTrack  resw 1
488 ADVHeads        resw 1
489 ADVOp           resb 1