summaryrefslogtreecommitdiffstats
path: root/contrib/syslinux-4.02/core/adv.inc
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/syslinux-4.02/core/adv.inc')
-rw-r--r--contrib/syslinux-4.02/core/adv.inc509
1 files changed, 509 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/core/adv.inc b/contrib/syslinux-4.02/core/adv.inc
new file mode 100644
index 0000000..0b45a6c
--- /dev/null
+++ b/contrib/syslinux-4.02/core/adv.inc
@@ -0,0 +1,509 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+;; Boston MA 02110-1301, USA; either version 2 of the License, or
+;; (at your option) any later version; incorporated herein by reference.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; adv.inc
+;;
+;; The auxillary data vector and its routines
+;;
+;; The auxillary data vector is a 512-byte aligned block that on the
+;; disk-based derivatives can be part of the syslinux file itself. It
+;; exists in two copies; when written, both copies are written (with a
+;; sync in between, if from the operating system.) The first two
+;; dwords are magic number and inverse checksum, then follows the data
+;; area as a tagged array similar to BOOTP/DHCP, finally a tail
+;; signature.
+;;
+;; Note that unlike BOOTP/DHCP, zero terminates the chain, and FF
+;; has no special meaning.
+;;
+
+;;
+;; List of ADV tags...
+;;
+ADV_BOOTONCE equ 1
+
+;;
+;; Other ADV data...
+;;
+ADV_MAGIC1 equ 0x5a2d2fa5 ; Head signature
+ADV_MAGIC2 equ 0xa3041767 ; Total checksum
+ADV_MAGIC3 equ 0xdd28bf64 ; Tail signature
+
+ADV_LEN equ 500 ; Data bytes
+
+adv_retries equ 6 ; Disk retries
+
+ section .adv
+ ; Introduce the ADVs to valid but blank
+adv0:
+.head resd 1
+.csum resd 1
+.data resb ADV_LEN
+.tail resd 1
+.end equ $
+adv1:
+.head resd 1
+.csum resd 1
+.data resb ADV_LEN
+.tail resd 1
+.end equ $
+ section .text16
+
+ ;
+ ; This is called after config file parsing, so we know
+ ; the intended location of the ADV
+ ;
+adv_init:
+ cmp byte [ADVDrive],-1
+ jne adv_read
+
+%if IS_SYSLINUX || IS_EXTLINUX
+ cmp word [ADVSectors],2 ; Not present?
+ jb adv_verify
+
+ mov eax,[Hidden]
+ mov edx,[Hidden+4]
+ add [ADVSec0],eax
+ adc [ADVSec0+4],edx
+ add [ADVSec1],eax
+ adc [ADVSec1+4],edx
+ mov al,[DriveNumber]
+ mov [ADVDrive],al
+ jmp adv_read
+%endif
+
+ ;
+ ; Initialize the ADV data structure in memory
+ ;
+adv_verify:
+ cmp byte [ADVDrive],-1 ; No ADV configured, still?
+ je .reset ; Then unconditionally reset
+
+ mov si,adv0
+ call .check_adv
+ jz .ok ; Primary ADV okay
+ mov si,adv1
+ call .check_adv
+ jz .adv1ok
+
+ ; Neither ADV is usable; initialize to blank
+.reset:
+ mov di,adv0
+ mov eax,ADV_MAGIC1
+ stosd
+ mov eax,ADV_MAGIC2
+ stosd
+ xor eax,eax
+ mov cx,ADV_LEN/4
+ rep stosd
+ mov eax,ADV_MAGIC3
+ stosd
+
+.ok:
+ ret
+
+ ; The primary ADV is bad, but the backup is OK
+.adv1ok:
+ mov di,adv0
+ mov cx,512/4
+ rep movsd
+ ret
+
+
+ ; SI points to the putative ADV; unchanged by routine
+ ; ZF=1 on return if good
+.check_adv:
+ push si
+ lodsd
+ cmp eax,ADV_MAGIC1
+ jne .done ; ZF=0, i.e. bad
+ xor edx,edx
+ mov cx,ADV_LEN/4+1 ; Remaining dwords
+.csum:
+ lodsd
+ add edx,eax
+ loop .csum
+ cmp edx,ADV_MAGIC2
+ jne .done
+ lodsd
+ cmp eax,ADV_MAGIC3
+.done:
+ pop si
+ ret
+
+;
+; adv_get: find an ADV string if present
+;
+; Input: DL = ADV ID
+; Output: CX = byte count (zero on not found)
+; SI = pointer to data
+; DL = unchanged
+;
+; Assumes CS == DS.
+;
+
+adv_get:
+ push ax
+ mov si,adv0.data
+ xor ax,ax ; Keep AH=0 at all times
+.loop:
+ lodsb ; Read ID
+ cmp al,dl
+ je .found
+ and al,al
+ jz .end
+ lodsb ; Read length
+ add si,ax
+ cmp si,adv0.tail
+ jb .loop
+ jmp .end
+
+.found:
+ lodsb
+ mov cx,ax
+ add ax,si ; Make sure it fits
+ cmp ax,adv0.tail
+ jbe .ok
+.end:
+ xor cx,cx
+.ok:
+ pop ax
+ ret
+
+;
+; adv_set: insert a string into the ADV in memory
+;
+; Input: DL = ADV ID
+; FS:BX = input buffer
+; CX = byte count (max = 255!)
+; Output: CF=1 on error
+; CX clobbered
+;
+; Assumes CS == DS == ES.
+;
+adv_set:
+ push ax
+ push si
+ push di
+ and ch,ch
+ jnz .overflow
+
+ push cx
+ mov si,adv0.data
+ xor ax,ax
+.loop:
+ lodsb
+ cmp al,dl
+ je .found
+ and al,al
+ jz .endz
+ lodsb
+ add si,ax
+ cmp si,adv0.tail
+ jb .loop
+ jmp .end
+
+.found: ; Found, need to delete old copy
+ lodsb
+ lea di,[si-2]
+ push di
+ add si,ax
+ mov cx,adv0.tail
+ sub cx,si
+ jb .nukeit
+ rep movsb ; Remove the old one
+ mov [di],ah ; Termination zero
+ pop si
+ jmp .loop
+.nukeit:
+ pop si
+ jmp .end
+.endz:
+ dec si
+.end:
+ ; Now SI points to where we want to put our data
+ pop cx
+ mov di,si
+ jcxz .empty
+ add si,cx
+ cmp si,adv0.tail-2
+ jae .overflow ; CF=0
+
+ mov si,bx
+ mov al,dl
+ stosb
+ mov al,cl
+ stosb
+ fs rep movsb
+
+.empty:
+ mov cx,adv0.tail
+ sub cx,di
+ xor ax,ax
+ rep stosb ; Zero-fill remainder
+
+ clc
+.done:
+ pop di
+ pop si
+ pop ax
+ ret
+.overflow:
+ stc
+ jmp .done
+
+;
+; adv_cleanup: checksum adv0 and copy to adv1
+; Assumes CS == DS == ES.
+;
+adv_cleanup:
+ pushad
+ mov si,adv0.data
+ mov cx,ADV_LEN/4
+ xor edx,edx
+.loop:
+ lodsd
+ add edx,eax
+ loop .loop
+ mov eax,ADV_MAGIC2
+ sub eax,edx
+ lea di,[si+4] ; adv1
+ mov si,adv0
+ mov [si+4],eax ; Store checksum
+ mov cx,(ADV_LEN+12)/4
+ rep movsd
+ popad
+ ret
+
+;
+; adv_write: write the ADV to disk.
+;
+; Location is in memory variables.
+; Assumes CS == DS == ES.
+;
+; Returns CF=1 if the ADV cannot be written.
+;
+adv_write:
+ push eax
+ mov eax,[ADVSec0]
+ or eax,[ADVSec0+4]
+ je .bad
+ mov eax,[ADVSec1]
+ or eax,[ADVSec1+4]
+ je .bad
+ cmp byte [ADVDrive],-1
+ je .bad
+
+ call adv_cleanup
+ mov ah,3 ; Write
+ call adv_read_write
+
+ clc
+ pop eax
+ ret
+.bad: ; No location for ADV set
+ stc
+ pop eax
+ ret
+
+;
+; adv_read: read the ADV from disk
+;
+; Location is in memory variables.
+; Assumes CS == DS == ES.
+;
+adv_read:
+ push ax
+ mov ah,2 ; Read
+ call adv_read_write
+ call adv_verify
+ pop ax
+ ret
+
+;
+; adv_read_write: disk I/O for the ADV
+;
+; On input, AH=2 for read, AH=3 for write.
+; Assumes CS == DS == ES.
+;
+adv_read_write:
+ mov [ADVOp],ah
+ pushad
+
+ ; Check for EDD
+ mov bx,55AAh
+ mov ah,41h ; EDD existence query
+ mov dl,[ADVDrive]
+ int 13h
+ mov si,.cbios
+ jc .noedd
+ cmp bx,0AA55h
+ jne .noedd
+ test cl,1
+ jz .noedd
+ mov si,.ebios
+.noedd:
+
+ mov eax,[ADVSec0]
+ mov edx,[ADVSec0+4]
+ mov bx,adv0
+ call .doone
+
+ mov eax,[ADVSec1]
+ mov edx,[ADVSec1+4]
+ mov bx,adv1
+ call .doone
+
+ popad
+ ret
+
+.doone:
+ push si
+ jmp si
+
+.ebios:
+ mov cx,adv_retries
+.eb_retry:
+ ; Form DAPA on stack
+ push edx
+ push eax
+ push es
+ push bx
+ push word 1 ; Sector count
+ push word 16 ; DAPA size
+ mov si,sp
+ pushad
+ mov dl,[ADVDrive]
+ mov ax,4000h
+ or ah,[ADVOp]
+ push ds
+ push ss
+ pop ds
+ int 13h
+ pop ds
+ popad
+ lea sp,[si+16] ; Remove DAPA
+ jc .eb_error
+ pop si
+ ret
+.eb_error:
+ loop .eb_retry
+ stc
+ pop si
+ ret
+
+.cbios:
+ push edx
+ push eax
+ push bp
+
+ and edx,edx ; > 2 TiB not possible
+ jnz .cb_overflow
+
+ mov dl,[ADVDrive]
+ and dl,dl
+ ; Floppies: can't trust INT 13h 08h, we better know
+ ; the geometry a priori, which means it better be our
+ ; boot device...
+ jns .noparm ; Floppy drive... urk
+
+ mov ah,08h ; Get disk parameters
+ int 13h
+ jc .noparm
+ and ah,ah
+ jnz .noparm
+ shr dx,8
+ inc dx
+ movzx edi,dx ; EDI = heads
+ and cx,3fh
+ movzx esi,cx ; ESI = sectors/track
+ jmp .parmok
+
+.noparm:
+ ; No CHS info... this better be our boot drive, then
+%if IS_SYSLINUX || IS_EXTLINUX
+ cmp dl,[DriveNumber]
+ jne .cb_overflow ; Fatal error!
+ movzx esi,word [bsSecPerTrack]
+ movzx edi,word [bsHeads]
+%else
+ ; Not a disk-based derivative... there is no hope
+ jmp .cb_overflow
+%endif
+
+.parmok:
+ ;
+ ; Dividing by sectors to get (track,sector): we may have
+ ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
+ ;
+ xor edx,edx
+ div esi
+ xor cx,cx
+ xchg cx,dx ; CX <- sector index (0-based)
+ ; EDX <- 0
+ ; eax = track #
+ div edi ; Convert track to head/cyl
+
+ ; Watch out for overflow, we might be writing!
+ cmp eax,1023
+ ja .cb_overflow
+
+ ;
+ ; Now we have AX = cyl, DX = head, CX = sector (0-based),
+ ; BP = sectors to transfer, SI = bsSecPerTrack,
+ ; ES:BX = data target
+ ;
+
+ shl ah,6 ; Because IBM was STOOPID
+ ; and thought 8 bits were enough
+ ; then thought 10 bits were enough...
+ inc cx ; Sector numbers are 1-based, sigh
+ or cl,ah
+ mov ch,al
+ mov dh,dl
+ mov dl,[ADVDrive]
+ mov al,01h ; Transfer one sector
+ mov ah,[ADVOp] ; Operation
+
+ mov bp,adv_retries
+.cb_retry:
+ pushad
+ int 13h
+ popad
+ jc .cb_error
+
+.cb_done:
+ pop bp
+ pop eax
+ pop edx
+ pop si
+ ret
+
+.cb_error:
+ dec bp
+ jnz .cb_retry
+.cb_overflow:
+ stc
+ jmp .cb_done
+
+ section .data16
+ alignz 8
+ADVSec0 dq 0 ; Not specified
+ADVSec1 dq 0 ; Not specified
+ADVDrive db -1 ; No ADV defined
+ADVCHSInfo db -1 ; We have CHS info for this drive
+
+ section .bss16
+ADVOp resb 1
+
+ section .text16