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;; 33ADV_BOOTONCE equ 1 34 35;; 36;; Other ADV data... 37;; 38ADV_MAGIC1 equ 0x5a2d2fa5 ; Head signature 39ADV_MAGIC2 equ 0xa3041767 ; Total checksum 40ADV_MAGIC3 equ 0xdd28bf64 ; Tail signature 41 42ADV_LEN equ 500 ; Data bytes 43 44adv_retries equ 6 ; Disk retries 45 46 section .data 47 global __syslinux_adv_ptr, __syslinux_adv_size 48__syslinux_adv_ptr: 49 dd adv0.data 50__syslinux_adv_size: 51 dd ADV_LEN 52 53 section .adv 54 ; Introduce the ADVs to valid but blank 55adv0: 56.head resd 1 57.csum resd 1 58.data resb ADV_LEN 59.tail resd 1 60.end equ $ 61adv1: 62.head resd 1 63.csum resd 1 64.data resb ADV_LEN 65.tail resd 1 66.end equ $ 67 section .text16 68 69 ; 70 ; This is called after config file parsing, so we know 71 ; the intended location of the ADV 72 ; 73 global adv_init 74adv_init: 75 cmp byte [ADVDrive],-1 76 jne adv_read 77 78%if IS_SYSLINUX || IS_EXTLINUX 79 cmp word [ADVSectors],2 ; Not present? 80 jb adv_verify 81 82 mov eax,[Hidden] 83 mov edx,[Hidden+4] 84 add [ADVSec0],eax 85 adc [ADVSec0+4],edx 86 add [ADVSec1],eax 87 adc [ADVSec1+4],edx 88 mov al,[DriveNumber] 89 mov [ADVDrive],al 90 jmp adv_read 91%endif 92 93 ; 94 ; Initialize the ADV data structure in memory 95 ; 96adv_verify: 97 cmp byte [ADVDrive],-1 ; No ADV configured, still? 98 je .reset ; Then unconditionally reset 99 100 mov si,adv0 101 call .check_adv 102 jz .ok ; Primary ADV okay 103 mov si,adv1 104 call .check_adv 105 jz .adv1ok 106 107 ; Neither ADV is usable; initialize to blank 108.reset: 109 mov di,adv0 110 mov eax,ADV_MAGIC1 111 stosd 112 mov eax,ADV_MAGIC2 113 stosd 114 xor eax,eax 115 mov cx,ADV_LEN/4 116 rep stosd 117 mov eax,ADV_MAGIC3 118 stosd 119 120.ok: 121 ret 122 123 ; The primary ADV is bad, but the backup is OK 124.adv1ok: 125 mov di,adv0 126 mov cx,512/4 127 rep movsd 128 ret 129 130 131 ; SI points to the putative ADV; unchanged by routine 132 ; ZF=1 on return if good 133.check_adv: 134 push si 135 lodsd 136 cmp eax,ADV_MAGIC1 137 jne .done ; ZF=0, i.e. bad 138 xor edx,edx 139 mov cx,ADV_LEN/4+1 ; Remaining dwords 140.csum: 141 lodsd 142 add edx,eax 143 loop .csum 144 cmp edx,ADV_MAGIC2 145 jne .done 146 lodsd 147 cmp eax,ADV_MAGIC3 148.done: 149 pop si 150 ret 151 152; 153; adv_get: find an ADV string if present 154; 155; Input: DL = ADV ID 156; Output: CX = byte count (zero on not found) 157; SI = pointer to data 158; DL = unchanged 159; 160; Assumes CS == DS. 161; 162 163adv_get: 164 push ax 165 mov si,adv0.data 166 xor ax,ax ; Keep AH=0 at all times 167.loop: 168 lodsb ; Read ID 169 cmp al,dl 170 je .found 171 and al,al 172 jz .end 173 lodsb ; Read length 174 add si,ax 175 cmp si,adv0.tail 176 jb .loop 177 jmp .end 178 179.found: 180 lodsb 181 mov cx,ax 182 add ax,si ; Make sure it fits 183 cmp ax,adv0.tail 184 jbe .ok 185.end: 186 xor cx,cx 187.ok: 188 pop ax 189 ret 190 191; 192; adv_set: insert a string into the ADV in memory 193; 194; Input: DL = ADV ID 195; FS:BX = input buffer 196; CX = byte count (max = 255!) 197; Output: CF=1 on error 198; CX clobbered 199; 200; Assumes CS == DS == ES. 201; 202adv_set: 203 push ax 204 push si 205 push di 206 and ch,ch 207 jnz .overflow 208 209 push cx 210 mov si,adv0.data 211 xor ax,ax 212.loop: 213 lodsb 214 cmp al,dl 215 je .found 216 and al,al 217 jz .endz 218 lodsb 219 add si,ax 220 cmp si,adv0.tail 221 jb .loop 222 jmp .end 223 224.found: ; Found, need to delete old copy 225 lodsb 226 lea di,[si-2] 227 push di 228 add si,ax 229 mov cx,adv0.tail 230 sub cx,si 231 jb .nukeit 232 rep movsb ; Remove the old one 233 mov [di],ah ; Termination zero 234 pop si 235 jmp .loop 236.nukeit: 237 pop si 238 jmp .end 239.endz: 240 dec si 241.end: 242 ; Now SI points to where we want to put our data 243 pop cx 244 mov di,si 245 jcxz .empty 246 add si,cx 247 cmp si,adv0.tail-2 248 jae .overflow ; CF=0 249 250 mov si,bx 251 mov al,dl 252 stosb 253 mov al,cl 254 stosb 255 fs rep movsb 256 257.empty: 258 mov cx,adv0.tail 259 sub cx,di 260 xor ax,ax 261 rep stosb ; Zero-fill remainder 262 263 clc 264.done: 265 pop di 266 pop si 267 pop ax 268 ret 269.overflow: 270 stc 271 jmp .done 272 273; 274; adv_cleanup: checksum adv0 and copy to adv1 275; Assumes CS == DS == ES. 276; 277adv_cleanup: 278 pushad 279 mov si,adv0.data 280 mov cx,ADV_LEN/4 281 xor edx,edx 282.loop: 283 lodsd 284 add edx,eax 285 loop .loop 286 mov eax,ADV_MAGIC2 287 sub eax,edx 288 lea di,[si+4] ; adv1 289 mov si,adv0 290 mov [si+4],eax ; Store checksum 291 mov cx,(ADV_LEN+12)/4 292 rep movsd 293 popad 294 ret 295 296; 297; adv_write: write the ADV to disk. 298; 299; Location is in memory variables. 300; Assumes CS == DS == ES. 301; 302; Returns CF=1 if the ADV cannot be written. 303; 304 global adv_write 305adv_write: 306 push eax 307 mov eax,[ADVSec0] 308 or eax,[ADVSec0+4] 309 je .bad 310 mov eax,[ADVSec1] 311 or eax,[ADVSec1+4] 312 je .bad 313 cmp byte [ADVDrive],-1 314 je .bad 315 316 call adv_cleanup 317 mov ah,3 ; Write 318 call adv_read_write 319 320 clc 321 pop eax 322 ret 323.bad: ; No location for ADV set 324 stc 325 pop eax 326 ret 327 328; 329; adv_read: read the ADV from disk 330; 331; Location is in memory variables. 332; Assumes CS == DS == ES. 333; 334adv_read: 335 push ax 336 mov ah,2 ; Read 337 call adv_read_write 338 call adv_verify 339 pop ax 340 ret 341 342; 343; adv_read_write: disk I/O for the ADV 344; 345; On input, AH=2 for read, AH=3 for write. 346; Assumes CS == DS == ES. 347; 348adv_read_write: 349 mov [ADVOp],ah 350 pushad 351 352 ; Check for EDD 353 mov bx,55AAh 354 mov ah,41h ; EDD existence query 355 mov dl,[ADVDrive] 356 int 13h 357 mov si,.cbios 358 jc .noedd 359 cmp bx,0AA55h 360 jne .noedd 361 test cl,1 362 jz .noedd 363 mov si,.ebios 364.noedd: 365 366 mov eax,[ADVSec0] 367 mov edx,[ADVSec0+4] 368 mov bx,adv0 369 call .doone 370 371 mov eax,[ADVSec1] 372 mov edx,[ADVSec1+4] 373 mov bx,adv1 374 call .doone 375 376 popad 377 ret 378 379.doone: 380 push si 381 jmp si 382 383.ebios: 384 mov cx,adv_retries 385.eb_retry: 386 ; Form DAPA on stack 387 push edx 388 push eax 389 push es 390 push bx 391 push word 1 ; Sector count 392 push word 16 ; DAPA size 393 mov si,sp 394 pushad 395 mov dl,[ADVDrive] 396 mov ax,4000h 397 or ah,[ADVOp] 398 push ds 399 push ss 400 pop ds 401 int 13h 402 pop ds 403 popad 404 lea sp,[si+16] ; Remove DAPA 405 jc .eb_error 406 pop si 407 ret 408.eb_error: 409 loop .eb_retry 410 stc 411 pop si 412 ret 413 414.cbios: 415 push edx 416 push eax 417 push bp 418 419 and edx,edx ; > 2 TiB not possible 420 jnz .cb_overflow 421 422 mov dl,[ADVDrive] 423 and dl,dl 424 ; Floppies: can't trust INT 13h 08h, we better know 425 ; the geometry a priori, which means it better be our 426 ; boot device... 427 jns .noparm ; Floppy drive... urk 428 429 mov ah,08h ; Get disk parameters 430 int 13h 431 jc .noparm 432 and ah,ah 433 jnz .noparm 434 shr dx,8 435 inc dx 436 movzx edi,dx ; EDI = heads 437 and cx,3fh 438 movzx esi,cx ; ESI = sectors/track 439 jmp .parmok 440 441.noparm: 442 ; No CHS info... this better be our boot drive, then 443%if IS_SYSLINUX || IS_EXTLINUX 444 cmp dl,[DriveNumber] 445 jne .cb_overflow ; Fatal error! 446 movzx esi,word [bsSecPerTrack] 447 movzx edi,word [bsHeads] 448%else 449 ; Not a disk-based derivative... there is no hope 450 jmp .cb_overflow 451%endif 452 453.parmok: 454 ; 455 ; Dividing by sectors to get (track,sector): we may have 456 ; up to 2^18 tracks, so we need to use 32-bit arithmetric. 457 ; 458 xor edx,edx 459 div esi 460 xor cx,cx 461 xchg cx,dx ; CX <- sector index (0-based) 462 ; EDX <- 0 463 ; eax = track # 464 div edi ; Convert track to head/cyl 465 466 ; Watch out for overflow, we might be writing! 467 cmp eax,1023 468 ja .cb_overflow 469 470 ; 471 ; Now we have AX = cyl, DX = head, CX = sector (0-based), 472 ; BP = sectors to transfer, SI = bsSecPerTrack, 473 ; ES:BX = data target 474 ; 475 476 shl ah,6 ; Because IBM was STOOPID 477 ; and thought 8 bits were enough 478 ; then thought 10 bits were enough... 479 inc cx ; Sector numbers are 1-based, sigh 480 or cl,ah 481 mov ch,al 482 mov dh,dl 483 mov dl,[ADVDrive] 484 mov al,01h ; Transfer one sector 485 mov ah,[ADVOp] ; Operation 486 487 mov bp,adv_retries 488.cb_retry: 489 pushad 490 int 13h 491 popad 492 jc .cb_error 493 494.cb_done: 495 pop bp 496 pop eax 497 pop edx 498 pop si 499 ret 500 501.cb_error: 502 dec bp 503 jnz .cb_retry 504.cb_overflow: 505 stc 506 jmp .cb_done 507 508 section .data16 509 alignz 8 510ADVSec0 dq 0 ; Not specified 511ADVSec1 dq 0 ; Not specified 512ADVDrive db -1 ; No ADV defined 513ADVCHSInfo db -1 ; We have CHS info for this drive 514 515 section .bss16 516ADVOp resb 1 517 518 section .text16 519