[e16e8f2] | 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 |
---|