1/* $MirOS: src/sys/arch/i386/stand/boot/srt0.S,v 1.85 2012/09/02 22:08:48 tg Exp $ */ 2 3/*- 4 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012 5 * Thorsten Glaser <tg@mirbsd.org> 6 * 7 * Provided that these terms and disclaimer and all copyright notices 8 * are retained or reproduced in an accompanying document, permission 9 * is granted to deal in this work without restriction, including un- 10 * limited rights to use, publicly perform, distribute, sell, modify, 11 * merge, give away, or sublicence. 12 * 13 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to 14 * the utmost extent permitted by applicable law, neither express nor 15 * implied; without malicious intent or gross negligence. In no event 16 * may a licensor, author or contributor be held liable for indirect, 17 * direct, other damage, loss, or other issues arising in any way out 18 * of dealing in the work, even if advised of the possibility of such 19 * damage or existence of a defect, except proven that it results out 20 * of said person's immediate fault when using the work as intended. 21 */ 22 23#include "stand/boot/cmd.h" 24 25 .intel_syntax noprefix 26 .text 27 .code16 28 29 /* extern */ 30 .globl real_to_prot 31 .globl prot_to_real 32 .globl boot 33 .globl _edata 34 .globl _end 35 .globl _rtt 36#ifdef USE_PXE 37 .globl have_pxe 38#endif 39 /* global */ 40 .globl _start 41 .globl bios_bootpte 42 .globl i386_userpt 43 .globl i386_biosdev 44 .globl i386_biosflags 45 .globl i386_dosdev 46 .globl pxe_bang 47 .globl pxe_plus 48 .globl pxecall_addr 49 .globl lmbm_num 50 .globl lmbm_ofs 51 52_start: cli 53 call Linit 54Lrval: .p2align 2 55 . = _start + 4 56 /* ffffddpp (f)lags user(p)artype (d)rive */ 57Ldrvi: .long 0x696D4F00 /* drive information and magic */ 58 i386_userpt = Ldrvi 59 i386_biosdev = Ldrvi + 1 60 i386_biosflags = Ldrvi + 2 61 /*- 62 * 01101101 = flags invalid 63 * xxxxxx00 = nothing special about drives 64 * xxxxxx01 = i386_dosdev valid, DOS interface 65 * xxxxxx10 = pxelinux or invalid FOOlinux 66 * xxxxxx11 = syslinux/extlinux/isolinux 67 * xxxxx1xx = probably booted via PXE 68 */ 69 i386_dosdev = Ldrvi + 3 70 /*- 71 * if PXE: 0 = do not scan, 1 = do scan 72 */ 73 .size i386_userpt,1 74 .size i386_biosdev,1 75 .size i386_biosflags,1 76 .size i386_dosdev,1 77 . = _start + 8 78pxe_bang: 79 .size pxe_bang,4 80 .long 0 /* address of !PXE structure */ 81 . = _start + 12 82pxe_plus: 83 .size pxe_plus,4 84 .long 0 /* address of PXENV+ structure */ 85 . = _start + 16 86bios_bootpte: 87 .size bios_bootpte,16 88 .long 0, 0, 0, 0 /* 16 bytes from initial DS:SI */ 89 . = _start + 32 90pxecall_addr: 91 .size pxecall_addr,4 92 .long 0 /* PXE RM entry point (FAR pointer) */ 93lmbm_num: 94 .size lmbm_num,4 95 .long 0 /* number of Loadable MultiBoot Modules */ 96lmbm_ofs: 97 .size lmbm_ofs,4 98 .long 0 /* address of LMBM table, if loaded */ 99 100#ifndef SMALL_BOOT 101 /* Multiboot header */ 102 .p2align 2 103Lmbhdr: .long 0x1BADB002 /* magic */ 104 .long 0x00010000 /* flags */ 105 .long -0x1BADB002-0x00010000 /* checksum */ 106 /* the addresses are all bounced to 1 MiB */ 107 .long Lmbhdr - SA_LINKADDR + 0x00100000 /* header_addr */ 108 .long 0x00100000 /* load_addr */ 109 .long 0 /* load_end_addr */ 110 .long 0 /* bss_end_addr */ 111 .long Lmbrun - SA_LINKADDR + 0x00100000 /* entry_addr */ 112#endif 113 114 /* pointer to ldbsd.com command line or 1 (DOS/COMBOOT PSP) */ 115Largp: .long 0 116 117Linit: /* qemu sucks, int3 doesn’t work */ 118 push ds 119 push si 120 xor si,si 121 mov ds,si 122 mov cl,0xCB 123 xchg ds:[si],cl 124 /* set a “b *0” to stop at this point */ 125 lcall 0x0000,0x0000 126 xchg ds:[si],cl 127 pop si 128 pop ds 129 130#ifndef SMALL_BOOT 131 mov cx,es 132 shl ecx,16 133 mov cx,bx /* ECX: PXENV+ */ 134 mov bp,sp 135 mov edi,[bp+6] /* EDI: !PXE */ 136 rol esi,16 137 mov si,ds /* ESI: SI:DS */ 138#endif 139 140 xor ebp,ebp 141 push ebp 142 popfd 143 pop bp 144 145 /* make cs:(e)bx = offset _start */ 146 lea ebx,[ebp + offset _start - offset Lrval] 147 /* make ebp = flat offset _start */ 148 mov bp,cs 149 shl ebp,4 150 add ebp,ebx 151 /* make ax = _start + 64K (approx.) */ 152 mov eax,ebp 153 shr eax,4 154 add ax,0x1000 155 /* set up initial stack */ 156 mov ss,ax 157 mov esp,0x00003FEC 158 159 /* first stage: before relocation */ 160 161 /* set up segment registers */ 162 mov ax,cs 163 mov ds,ax 164 mov es,ax 165 166#ifdef SMALL_BOOT 167 xor eax,eax 168 mov ah,dl 169 mov al,ds:[ebx + offset Ldrvi - offset _start] 170 mov ds:[ebx + offset Ldrvi - offset _start],eax 171#else 172 /* store away structure pointers */ 173 mov ds:[ebx + offset pxe_plus - offset _start],ecx 174 mov ds:[ebx + offset pxe_bang - offset _start],edi 175 cmp byte ptr ds:[ebx + offset i386_biosflags - offset _start],0x6D 176 je 1f 177 mov ds,si 178 rol esi,16 179 lea di,[ebx + offset bios_bootpte - offset _start] 180 movsd 181 movsd 182 movsd 183 movsd 184 mov ax,cs 185 mov ds,ax 186 jmp 3f 1871: xor eax,eax 188 mov ah,dl 189 cmp ebp,0x00007C00 190 jne 2f 191 or eax,0x01040000 /* PXE, do scan */ 1922: mov al,ds:[ebx + offset Ldrvi - offset _start] 193 mov ds:[ebx + offset Ldrvi - offset _start],eax 1943: /* find out if we're a DOS or SYSLINUX COMBOOT programme */ 195 cmp bx,0x0100 196 jne Lnocom 197 cmp word ptr ds:[0],0x20CD 198 jne Lnocom 199 200 /* store magic flag to Largp for using the command line */ 201 inc byte ptr ds:[ebx + offset Largp - offset _start] 202 203 push ebp 204 push ebx 205 206 xor eax,eax 207 /* from DOS or SYSLINUX: no PXE or bootpte */ 208 lea edi,[ebx + offset pxe_bang - offset _start] 209 mov cx,6 210 rep stosd 211 212 mov ah,0x30 /* get DOS version */ 213 int 0x21 214 cmp eax,0x59530000 215 jne Lnolx 216 cmp ecx,0x4E490000 217 jne Lnolx 218 cmp edx,0x58550000 219 jne Lnolx 220 cmp ebx,0x4C530000 221 jne Lnolx 222 223 /* SYSLINUX */ 224 mov ax,0x0005 /* SYSLINUX: force text mode */ 225 int 0x22 226 mov ax,0x000A /* SYSLINUX: get information */ 227 int 0x22 228 push cs 229 pop ds 230 pop ecx 231 cmp al,0x31 232 jb Linvlinux 233 je Lsyslinux 234 cmp al,0x34 235 ja Linvlinux 236 je Lextlinux 237 cmp al,0x33 238 je Lisolinux 239 240Lpxelinux: 241 mov ax,es 242 shl eax,16 243 mov ax,bx 244 mov ds:[ecx + offset pxe_bang - offset _start],eax 245 mov ds:[ecx + offset pxe_plus - offset _start],eax 246 xor edx,edx 247 mov dh,4 /* probably PXE :) but do not scan */ 248 mov bx,3 /* clean up but retain PXE and UNDI */ 249 jmp Lislx 250 251Lsyslinux: 252Lextlinux: 253 mov eax,es:[bx] 254 mov ds:[ecx + offset bios_bootpte - offset _start],eax 255 mov eax,es:[bx+4] 256 mov ds:[ecx + offset bios_bootpte - offset _start + 4],eax 257 mov eax,es:[bx+8] 258 mov ds:[ecx + offset bios_bootpte - offset _start + 8],eax 259 mov eax,es:[bx+12] 260 mov ds:[ecx + offset bios_bootpte - offset _start + 12],eax 261Lisolinux: 262Linvlinux: 263 and edx,0xFF 264 mov dh,1 265 xor bx,bx /* clean up everything */ 266Lislx: or dh,2 267 shl edx,8 268 mov dl,ds:[ecx + offset Ldrvi - offset _start] 269 mov ds:[ecx + offset Ldrvi - offset _start],edx 270 271 mov ax,0x000C /* SYSLINUX: final cleanup */ 272 mov dx,bx /* see above */ 273 int 0x22 274 jmp Liscom 275 276Lnolx: /* DOS */ 277 mov ah,0x19 278 int 0x21 279 push cs 280 pop ds 281 pop ecx 282 lea ebx,[ecx + offset Ldrvi - offset _start] 283 mov ah,al /* ign ign dosdrv dosdrv */ 284 cmp al,2 285 jb 1f /* floppy (BIOS 00h, 01h) for DOS A:, B: */ 286 mov al,0x80 /* fake BIOS 80h for DOS C:, D:, E:, ... */ 2871: shl eax,8 /* ign dosdrv biosdrv zero */ 288 inc ax /* 01 = flag: DOS drive valid */ 289 xchg ah,al /* ign dosdrv flag=1 biosdrv */ 290 shl eax,8 /* dosdrv flag biosdrv zero */ 291 mov al,ds:[bx] /* dosdrv flag biosdrv partp */ 292 mov ds:[bx],eax 293 294Liscom: pop ebp 295 xor eax,eax 296 push eax 297 popfd 298Lnocom: /* flags are (already) okay */ 299#endif 300 301 /* load source address (_start) normalised */ 302 mov ebx,ebp 303 shr ebx,4 304 /* subtract 128 for DOS/COMBOOT PSP command line */ 305 sub bx,(128/16) 306 mov ds,bx 307 mov si,bp 308 and si,0x000F 309 310 /* check if we need to relocate */ 311 cmp ebp,SA_LINKADDR 312 je LdoRel /* to set up the stack */ 313 cmp ebp,0x1C000 314 jbe LdoRel /* way below target */ 315 cmp ebp,0x50000 316 jae LdoRel /* somewhat above target */ 317 318 /* eek, relocate twice */ 319 mov ax,0x7000 320 mov ss,ax 321 mov sp,0x3FFC 322 mov ax,0x6000 323 push ax 324 /* subtract 128 for DOS/COMBOOT PSP command line */ 325 sub ax,(128/16) 326 mov es,ax 327 xor di,di 328 mov eax,offset LdoRel - offset _start 329 push ax 330 push es 331 push di 332 /* min. 0xFF00 max. code size + 0x80 PSP cmdline */ 333 mov cx,0xFFF0 334 rep movsb 335 pop si 336 pop ds 337 lret 338 339LdoRel: mov ax,0x3000 340 mov ss,ax 341 mov esp,0x0000FF7C 342 cmp ebp,SA_LINKADDR 343 je LisRel 344 345 /* subtract 128 for DOS/COMBOOT PSP command line */ 346 mov ax,(SA_LINKSEG - (128/16)) 347 mov es,ax 348 xor di,di 349 /* same as above */ 350 mov cx,0xFFF0 351 rep movsb 352 353 /* assumes flags=0, SS:ESP set up to 3000:0000FF7Ch */ 354LisRel: mov ax,SA_LINKSEG 355 mov ds,ax 356 mov es,ax 357 push ax 358 mov eax,offset Lstart - offset _start 359 push ax 360 lret 361 362 /* whew, we're relocated */ 363Lstart: 364 /* check for presence of command line */ 365 mov esi,offset Largp - offset _start 366 mov eax,[si] 367 or eax,eax 368 jz Lnocmd 369#ifdef BOOTSELECT_HOOK 370 xor ebx,ebx 371#endif 372 cmp eax,1 /* magic */ 373 jne Liscmd 374 /* we have a DOS/COMBOOT PSP, analyse it */ 375 mov ax,ds 376 push ax 377 sub ax,(128/16) 378 mov ds,ax 379 xor cx,cx 380 mov cl,byte ptr ds:[0] 381 mov si,1 3821: or cx,cx 383 jz Lpspno 384 lodsb 385 cmp al,0x09 /* tab */ 386 je 2f 387 cmp al,0x0D /* CR */ 388 je 2f 389 cmp al,0x20 /* space */ 390 jne 3f 3912: dec cx 392 jmp 1b 3933: dec si 394 mov di,si 395 add di,cx 396 dec di 3974: mov al,[di] 398 cmp al,0x09 /* tab */ 399 je 5f 400 cmp al,0x0D /* CR */ 401 je 5f 402 cmp al,0x20 /* space */ 403 jne 6f 4045: dec cx 405 jz Lpspno 406 dec di 407 jmp 4b 4086: inc di 409 xor eax,eax 410 mov [di],al /* convert to NUL-terminated */ 411 /* DS:SI now points to NUL-terminated argv (SI < 0x80) */ 412 mov ax,ds 413 shl eax,4 414 add ax,si 415 pop ds 416 /* store flat pointer to NUL-terminated argv into Largp */ 417 mov esi,offset Largp - offset _start 418 mov [si],eax 419#ifdef BOOTSELECT_HOOK 420 xor ebx,ebx 421#endif 422 jmp Liscmd 423 424Lpspno: pop ds 425 xor eax,eax 426 mov esi,offset Largp - offset _start 427 mov [si],eax 428Lnocmd: /* no command line found */ 429#ifdef BOOTSELECT_HOOK 430 sti 431 .globl Lhook 432 call Lhook 433 mov ebx,eax 434#endif 435Liscmd: /* a command line was found */ 436 437 call real_to_prot 438Lsta32: .code32 439 /* ensure stack is 32-bit aligned */ 440 mov esp,0x0003FF7C 441 /* zero out .bss section */ 442 xor eax,eax 443 push eax 444 popfd 445 mov ecx,offset _end 446 mov edi,offset _edata 447 sub ecx,edi 448 rep stosb 449 450 /* zero out stack segment lower parts */ 451 mov edi,offset ssbss_beg 452 mov ecx,offset ssbss_end - offset ssbss_beg 453 rep stosb 454 455#ifdef BOOTSELECT_HOOK 456 /* store user choice */ 457 mov [hook_value],ebx 458#endif 459 460 /* store command line, if any */ 461 mov esi,[Largp] 462 or esi,esi 463 jz 1f 464 mov ecx,(CMD_BUFF_SIZE - 1) 465 mov edi,offset cmd_buf 466 rep movsb 467 /* NUL-terminate potentially too long multiboot cmdline */ 468 mov al,0 469 stosb 4701: 471 472 movzx eax,byte ptr [i386_biosdev] 473 push eax 474 call boot 475 jmp _rtt 476 477#ifndef SMALL_BOOT 478 /* Multiboot entry point */ 479 .p2align 4,0x90 480Lmbrun: mov esp,0x0003FF7C 481 xor eax,eax 482 push eax 483 popfd 484 485 /* set a “b *0” to stop at this point */ 486 push [eax] 487 mov byte ptr [eax],0xC3 488 call eax 489 pop [eax] 490 491 mov esi,0x00100000 492 mov edi,SA_LINKADDR 493 mov ecx,0x4000 494 rep movsd 495 mov eax,offset Lmb2rm 496 jmp eax 497 /* relocated */ 498Lmb2rm: mov edi,offset Ldrvi 499 mov edx,[ebx+12] /* boot_device */ 500 shr edx,16 501 mov eax,edx 502 mov al,[edi] /* user partition type */ 503 stosd /* drive information */ 504 xor eax,eax 505 stosd /* pxe_bang */ 506 stosd /* pxe_plus */ 507 stosd /* partition */ 508 stosd /* partition */ 509 stosd /* partition */ 510 stosd /* partition */ 511#ifdef USE_PXE 512 mov [have_pxe],eax /* do not even try */ 513#endif 514 515 mov eax,[ebx] 516 and eax,(1 << 2) /* do we have command line? */ 517 jz 1f /* nope */ 518 mov esi,[ebx+16] /* pointer */ 519 /* 520 * annoyingly enough, the first word on the command line 521 * is our own pathname, so we must skip it 522 */ 5234: lodsb 524 or al,al /* NUL */ 525 jz 1f 526 cmp al,0x09 /* tab */ 527 je 2f 528 cmp al,0x0A /* LF */ 529 je 2f 530 cmp al,0x0D /* CR */ 531 je 2f 532 cmp al,0x20 /* space */ 533 jne 4b 5342: lodsb 535 or al,al /* NUL */ 536 jz 1f 537 cmp al,0x09 /* tab */ 538 je 2b 539 cmp al,0x0A /* LF */ 540 je 2b 541 cmp al,0x0D /* CR */ 542 je 2b 543 cmp al,0x20 /* space */ 544 je 2b 545 dec esi 546 mov edi,esi 547 mov ecx,CMD_BUFF_SIZE 548 xor eax,eax 549 repne scasb 5503: dec edi 551 mov al,[edi] 552 cmp al,0x09 /* tab */ 553 je 3b 554 cmp al,0x0A /* LF */ 555 je 3b 556 cmp al,0x0D /* CR */ 557 je 3b 558 cmp al,0x20 /* space */ 559 je 3b 560 561 /* got a non-empty command line */ 562 mov byte ptr [edi+1],0 563 mov [Largp],esi 564 565 /* got no command line */ 5661: mov eax,[ebx] 567 and eax,(1 << 3) /* do we have modules? */ 568 jz Lnombm /* nope */ 569 mov eax,[ebx+20] /* how many? */ 570 mov [lmbm_num],eax 571 mov eax,[ebx+24] /* module information */ 572 mov [lmbm_ofs],eax 573Lnombm: 574 575 lgdt Gdtr 576 call prot_to_real /* converts stack */ 577 .code16 578 jmp LisRel 579#endif 580 581#ifdef USE_PXE 582 .code32 583 .globl pxecall_bang 584pxecall_bang: 585 push ebp 586 mov ebp,esp 587 pushfd 588 push ebx 589 push esi 590 push edi 591 592 mov ebx,[ebp+8] 593 mov edi,offset pxe_command_buf - offset bounce_buf 594 595 call prot_to_real 596 .code16 597 sti 598 599 push ss 600 push di 601 push bx 602 lcall ds:[32] /* pxecall_addr */ 603 add sp,6 604 movzx ebx,ax 605 606 call real_to_prot 607 .code32 608 609 mov eax,ebx 610 pop edi 611 pop esi 612 pop ebx 613 popfd 614 pop ebp 615 ret 616 617 .globl pxecall_plus 618pxecall_plus: 619 push ebp 620 mov ebp,esp 621 pushfd 622 push ebx 623 push esi 624 push edi 625 626 mov ebx,[ebp+8] 627 mov edi,offset pxe_command_buf - offset bounce_buf 628 629 call prot_to_real 630 .code16 631 sti 632 633 push ss 634 pop es 635 lcall ds:[32] /* pxecall_addr */ 636 movzx ebx,ax 637 638 call real_to_prot 639 .code32 640 641 mov eax,ebx 642 pop edi 643 pop esi 644 pop ebx 645 popfd 646 pop ebp 647 ret 648#endif 649 650 651 bounce_buf = 0x30000 652 .globl bounce_buf 653 .size bounce_buf, 4096 654 655 crc_table = bounce_buf + 4096 656 .globl crc_table 657 .size crc_table, 1024 658 659 pxe_command_buf = crc_table + 1024 660 .globl pxe_command_buf 661 .size pxe_command_buf, 256 662 663 sa_fixed_table = pxe_command_buf + 256 664 .globl sa_fixed_table 665 .size sa_fixed_table, 2176 666 667 biosdev_lba_buf = sa_fixed_table + 2176 668 .globl biosdev_lba_buf 669 .size biosdev_lba_buf, 16 670 671 cmd_buf = biosdev_lba_buf + 16 672 .globl cmd_buf 673 .size cmd_buf, CMD_BUFF_SIZE 674 675 /* last; size unknown (<0x1000) */ 676 cmd = cmd_buf + CMD_BUFF_SIZE 677 .globl cmd 678 .size cmd, CMD_STRUCT_SIZE 679 680 ssbss_beg = bounce_buf 681 ssbss_end = cmd + 0x0900 682