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 ;; 33 ADV_BOOTONCE equ 1 34 35 ;; 36 ;; Other ADV data... 37 ;; 38 ADV_MAGIC1 equ 0x5a2d2fa5 ; Head signature 39 ADV_MAGIC2 equ 0xa3041767 ; Total checksum 40 ADV_MAGIC3 equ 0xdd28bf64 ; Tail signature 41 42 ADV_LEN equ 500 ; Data bytes 43 44 adv_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 55 adv0: 56 .head resd 1 57 .csum resd 1 58 .data resb ADV_LEN 59 .tail resd 1 60 .end equ $ 61 adv1: 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 74 adv_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 ; 96 adv_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 163 adv_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 ; 202 adv_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 ; 277 adv_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 305 adv_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 ; 334 adv_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 ; 348 adv_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 510 ADVSec0 dq 0 ; Not specified 511 ADVSec1 dq 0 ; Not specified 512 ADVDrive db -1 ; No ADV defined 513 ADVCHSInfo db -1 ; We have CHS info for this drive 514 515 section .bss16 516 ADVOp resb 1 517 518 section .text16 519