1 ;; -----------------------------------------------------------------------
3 ;; Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
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 ;; -----------------------------------------------------------------------
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
26 ;; Note that unlike BOOTP/DHCP, zero terminates the chain, and FF
27 ;; has no special meaning.
31 ;; List of ADV tags...
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
47 ; Introduce the ADVs to valid but blank
63 ; This is called after config file parsing, so we know
64 ; the intended location of the ADV
67 cmp byte [ADVDrive],-1
70 %if IS_SYSLINUX || IS_EXTLINUX
71 cmp word [ADVSectors],2 ; Not present?
75 ; Update pointers to default ADVs...
80 mov eax,[bx+SectorPtrs] ; First ADV sector
81 mov edx,[bx+SectorPtrs+4] ; Second ADV sector
92 ; Initialize the ADV data structure in memory
95 cmp byte [ADVDrive],-1 ; No ADV configured, still?
96 je .reset ; Then unconditionally reset
100 jz .ok ; Primary ADV okay
105 ; Neither ADV is usable; initialize to blank
121 ; The primary ADV is bad, but the backup is OK
129 ; SI points to the putative ADV; unchanged by routine
130 ; ZF=1 on return if good
135 jne .done ; ZF=0, i.e. bad
137 mov cx,ADV_LEN/4+1 ; Remaining dwords
151 ; adv_get: find an ADV string if present
154 ; Output: CX = byte count (zero on not found)
155 ; SI = pointer to data
164 xor ax,ax ; Keep AH=0 at all times
180 add ax,si ; Make sure it fits
190 ; adv_set: insert a string into the ADV in memory
193 ; FS:BX = input buffer
194 ; CX = byte count (max = 255!)
195 ; Output: CF=1 on error
198 ; Assumes CS == DS == ES.
222 .found: ; Found, need to delete old copy
230 rep movsb ; Remove the old one
231 mov [di],ah ; Termination zero
240 ; Now SI points to where we want to put our data
259 rep stosb ; Zero-fill remainder
272 ; adv_cleanup: checksum adv0 and copy to adv1
273 ; Assumes CS == DS == ES.
288 mov [si+4],eax ; Store checksum
289 mov cx,(ADV_LEN+12)/4
295 ; adv_write: write the ADV to disk.
297 ; Location is in memory variables.
298 ; Assumes CS == DS == ES.
300 ; Returns CF=1 if the ADV cannot be written.
303 cmp dword [ADVSec0],0
305 cmp dword [ADVSec1],0
307 cmp byte [ADVDrive],-1
318 .bad: ; No location for ADV set
323 ; adv_read: read the ADV from disk
325 ; Location is in memory variables.
326 ; Assumes CS == DS == ES.
337 ; adv_read_write: disk I/O for the ADV
339 ; On input, AH=2 for read, AH=3 for write.
340 ; Assumes CS == DS == ES.
348 mov ah,41h ; EDD existence query
372 xor edx,edx ; Zero-extend LBA
384 push word 1 ; Sector count
385 push word 16 ; DAPA size
397 lea sp,[si+16] ; Remove DAPA
414 ; Floppies: can't trust INT 13h 08h, we better know
415 ; the geometry a priori, which means it better be our
417 jns .noparm ; Floppy drive... urk
419 mov ah,08h ; Get disk parameters
426 movzx edi,dx ; EDI = heads
428 movzx esi,cx ; ESI = sectors/track
432 ; No CHS info... this better be our boot drive, then
433 %if IS_SYSLINUX || IS_EXTLINUX
435 jne .cb_overflow ; Fatal error!
436 movzx esi,word [bsSecPerTrack]
437 movzx edi,word [bsHeads]
439 ; Not a disk-based derivative... there is no hope
445 ; Dividing by sectors to get (track,sector): we may have
446 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
450 xchg cx,dx ; CX <- sector index (0-based)
453 div edi ; Convert track to head/cyl
455 ; Watch out for overflow, we might be writing!
460 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
461 ; BP = sectors to transfer, SI = bsSecPerTrack,
462 ; ES:BX = data target
465 shl ah,6 ; Because IBM was STOOPID
466 ; and thought 8 bits were enough
467 ; then thought 10 bits were enough...
468 inc cx ; Sector numbers are 1-based, sigh
473 mov al,01h ; Transfer one sector
474 mov ah,[ADVOp] ; Operation
499 ADVSec0 dd 0 ; Not specified
500 ADVSec1 dd 0 ; Not specified
501 ADVDrive db -1 ; No ADV defined
502 ADVCHSInfo db -1 ; We have CHS info for this drive