diff options
Diffstat (limited to 'contrib/syslinux-4.02/core/adv.inc')
-rw-r--r-- | contrib/syslinux-4.02/core/adv.inc | 509 |
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 |