1#include "x16.h" 2#include "mem.h" 3 4#define WRMSR BYTE $0x0F; BYTE $0x30 /* WRMSR, argument in AX/DX (lo/hi) */ 5#define RDTSC BYTE $0x0F; BYTE $0x31 /* RDTSC, result in AX/DX (lo/hi) */ 6#define RDMSR BYTE $0x0F; BYTE $0x32 /* RDMSR, result in AX/DX (lo/hi) */ 7 8#ifdef PXE 9#define PDB 0x90000 /* temporary page tables (24KB) */ 10#else 11#define PDB 0x08000 12#endif PXE 13 14#define NoScreenBlank 1 15/*#define ResetDiscs 1*/ 16 17TEXT origin(SB), $0 18 /* 19 * This part of l.s is used only in the boot kernel. 20 * It assumes that we are in real address mode, i.e., 21 * that we look like an 8086. 22 * 23 * Make sure the segments are reasonable. 24 * If we were started directly from the BIOS 25 * (i.e. no MS-DOS) then DS may not be 26 * right. 27 */ 28 MOVW CS, AX 29 MOVW AX, DS 30 31#ifdef NoScreenBlank 32 /* 33 * Get the current video mode. If it isn't mode 3, 34 * set text mode 3. 35 * Well, no. Windows95 won't co-operate here so we have 36 * to explicitly set mode 3. 37 */ 38 XORL AX, AX 39 MOVB $0x0F, AH 40 INT $0x10 /* get current video mode in AL */ 41 CMPB AL, $03 42 JEQ sayhello 43#endif /* NoScreenBlank */ 44 XORL AX, AX 45 MOVB $0x03, AL 46 INT $0x10 /* set video mode in AL */ 47 48sayhello: 49 LWI(hello(SB), rSI) 50 CALL16(biosputs(SB)) 51 52#ifdef ResetDiscs 53 XORL AX, AX /* reset disc system */ 54 XORL DX, DX 55 MOVB $0x80, DL 56 INT $0x13 57#endif /* ResetDiscs */ 58 59#ifdef DOTCOM 60/* 61 * relocate everything to a half meg and jump there 62 * - looks weird because it is being assembled by a 32 bit 63 * assembler for a 16 bit world 64 * 65 * only b.com does this - not 9load 66 */ 67 MOVL $0,BX 68 INCL BX 69 SHLL $15,BX 70 MOVL BX,CX 71 MOVW BX,ES 72 MOVL $0,SI 73 MOVL SI,DI 74 CLD 75 REP 76 MOVSL 77 78 /* 79 * Jump to the copied image; 80 * fix up the DS for the new location. 81 */ 82 FARJUMP16(0x8000, _start8000(SB)) 83 84TEXT _start8000(SB), $0 85 MFSR(rCS, rAX) /* fix up DS, ES (0x8000) */ 86 MTSR(rAX, rDS) 87 MTSR(rAX, rES) 88 89 /* 90 * If we are already in protected mode, have to get back 91 * to real mode before trying any privileged operations 92 * (like going into protected mode...). 93 * Try to reset with a restart vector. 94 */ 95 MFCR(rCR0, rAX) /* are we in protected mode? */ 96 ANDI(0x0001, rAX) 97 JEQ _real 98 99 CLR(rBX) 100 MTSR(rBX, rES) 101 102 LWI(0x0467, rBX) /* reset entry point */ 103 LWI(_start8000(SB), rAX) /* offset within segment */ 104 BYTE $0x26 105 BYTE $0x89 106 BYTE $0x07 /* MOVW AX, ES:[BX] */ 107 LBI(0x69, rBL) 108 MFSR(rCS, rAX) /* segment */ 109 BYTE $0x26 110 BYTE $0x89 111 BYTE $0x07 /* MOVW AX, ES:[BX] */ 112 113 CLR(rDX) 114 OUTPORTB(0x70, 0x8F) 115 OUTPORTB(0x71, 0x0A) 116 117 FARJUMP16(0xFFFF, 0x0000) /* reset */ 118#endif /* DOTCOM */ 119 120_real: 121 122/* 123 * do things that need to be done in real mode. 124 * the results get written to CONFADDR (0x1200) 125 * in a series of <4-byte-magic-number><block-of-data> 126 * the data length is dependent on the magic number. 127 * 128 * this gets parsed by conf.c:/^readlsconf 129 * 130 * N.B. CALL16 kills rDI, so we can't call anything. 131 */ 132 LWI(0x0000, rAX) 133 MTSR(rAX, rES) 134 LWI(0x1200, rDI) 135 136/* 137 * turn off interrupts 138 */ 139 CLI 140 141/* 142 * detect APM1.2 bios support 143 */ 144 /* save DI */ 145 SW(rDI, rock(SB)) 146 147 /* disconnect anyone else */ 148 LWI(0x5304, rAX) 149 LWI(0x0000, rBX) 150 INT $0x15 151 152 /* connect */ 153 CLC 154 LWI(0x5303, rAX) 155 LWI(0x0000, rBX) 156 INT $0x15 157 CLI /* apm put interrupts back? */ 158 159 JC noapm 160 161 OPSIZE; PUSHR(rSI) 162 OPSIZE; PUSHR(rBX) 163 PUSHR(rDI) 164 PUSHR(rDX) 165 PUSHR(rCX) 166 PUSHR(rAX) 167 168 /* put DI, ES back */ 169 LW(rock(SB), rDI) 170 LWI(0x0000, rAX) 171 MTSR(rAX, rES) 172 173 /* 174 * write APM data. first four bytes are APM\0. 175 */ 176 LWI(0x5041, rAX) 177 STOSW 178 179 LWI(0x004d, rAX) 180 STOSW 181 182 LWI(8, rCX) 183apmmove: 184 POPR(rAX) 185 STOSW 186 LOOP apmmove 187 188noapm: 189 190/* 191 * end of real mode hacks: write terminator, put ES back. 192 */ 193 LWI(0x0000, rAX) 194 STOSW 195 STOSW 196 197 MFSR(rCS, rAX) /* fix up ES (0x8000) */ 198 MTSR(rAX, rES) 199 200/* 201 * goto protected mode 202 */ 203/* MOVL tgdtptr(SB),GDTR /**/ 204 BYTE $0x0f 205 BYTE $0x01 206 BYTE $0x16 207 WORD $tgdtptr(SB) 208 209 LWI(1, rAX) 210 /* MOV AX,MSW */ 211 BYTE $0x0F; BYTE $0x01; BYTE $0xF0 212 213/* 214 * clear prefetch queue (weird code to avoid optimizations) 215 */ 216 /* JMP .+2 */ 217 BYTE $0xEB 218 BYTE $0x00 219 220/* 221 * set all segs 222 */ 223/* MOVW $SELECTOR(1, SELGDT, 0),AX /**/ 224 BYTE $0xc7 225 BYTE $0xc0 226 WORD $SELECTOR(1, SELGDT, 0) 227 MOVW AX,DS 228 MOVW AX,SS 229 MOVW AX,ES 230 MOVW AX,FS 231 MOVW AX,GS 232 233/* JMPFAR SELECTOR(2, SELGDT, 0):$mode32bit(SB) /**/ 234 BYTE $0x66 235 BYTE $0xEA 236 LONG $mode32bit-KZERO(SB) 237 WORD $SELECTOR(2, SELGDT, 0) 238 239TEXT mode32bit(SB),$0 240 /* 241 * make a bottom level page table page that maps the first 242 * 16 meg of physical memory 243 */ 244 MOVL $PDB, DI /* clear 6 pages for the tables etc. */ 245 XORL AX, AX 246 MOVL $(6*BY2PG), CX 247 SHRL $2, CX 248 249 CLD 250 REP; STOSL 251 252 MOVL $PDB, AX /* phys addr of temporary page table */ 253 MOVL $(4*1024),CX /* pte's per page */ 254 MOVL $((((4*1024)-1)<<PGSHIFT)|PTEVALID|PTEKERNEL|PTEWRITE),BX 255setpte: 256 MOVL BX,-4(AX)(CX*4) 257 SUBL $(1<<PGSHIFT),BX 258 LOOP setpte 259 260 /* 261 * make a top level page table page that maps the first 262 * 16 meg of memory to 0 thru 16meg and to KZERO thru KZERO+16meg 263 */ 264 MOVL AX,BX 265 ADDL $(4*BY2PG),AX 266 ADDL $(PTEVALID|PTEKERNEL|PTEWRITE),BX 267 MOVL BX,0(AX) 268 MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+0)(AX) 269 ADDL $BY2PG,BX 270 MOVL BX,4(AX) 271 MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+4)(AX) 272 ADDL $BY2PG,BX 273 MOVL BX,8(AX) 274 MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+8)(AX) 275 ADDL $BY2PG,BX 276 MOVL BX,12(AX) 277 MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+12)(AX) 278 279 /* 280 * point processor to top level page & turn on paging 281 * 282 * this produces the apparently harmless "VMX|F(125):468 Dis 0x0:0x0" 283 * message in the VMware log. 284 */ 285 MOVL AX,CR3 286 MOVL CR0,AX 287 ORL $0X80000000,AX 288 MOVL AX,CR0 289 290 /* 291 * use a jump to an absolute location to get the PC into 292 * KZERO. 293 */ 294 LEAL tokzero(SB),AX 295 JMP* AX 296 297/* 298 * When we load 9load from DOS, the bootstrap jumps 299 * to the instruction right after `JUMP', which gets 300 * us into kzero. 301 * 302 * The name prevents it from being optimized away. 303 */ 304TEXT jumplabel(SB), $0 305 BYTE $'J'; BYTE $'U'; BYTE $'M'; BYTE $'P' 306 307 LEAL tokzero(SB),AX 308 JMP* AX 309 310TEXT tokzero(SB),$0 311 /* 312 * Clear BSS 313 */ 314 LEAL edata(SB),SI 315 MOVL SI,DI 316 ADDL $4,DI 317 MOVL $0,AX 318 MOVL AX,(SI) 319 LEAL end(SB),CX 320 SUBL DI,CX 321 SHRL $2,CX 322 CLD 323 REP 324 MOVSL 325 326 /* 327 * stack and mach 328 */ 329 MOVL $mach0(SB),SP 330 MOVL SP,m(SB) 331 MOVL $0,0(SP) 332 ADDL $(MACHSIZE-4),SP /* start stack above machine struct */ 333 334 CALL main(SB) 335 336loop: 337 JMP loop 338 339GLOBL mach0+0(SB), $MACHSIZE 340GLOBL m(SB), $4 341 342/* 343 * gdt to get us to 32-bit/segmented/unpaged mode 344 */ 345TEXT tgdt(SB),$0 346 347 /* null descriptor */ 348 LONG $0 349 LONG $0 350 351 /* data segment descriptor for 4 gigabytes (PL 0) */ 352 LONG $(0xFFFF) 353 LONG $(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW) 354 355 /* exec segment descriptor for 4 gigabytes (PL 0) */ 356 LONG $(0xFFFF) 357 LONG $(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR) 358 359 /* exec segment descriptor for 4 gigabytes (PL 0) 16-bit */ 360 LONG $(0xFFFF) 361 LONG $(SEGG|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR) 362 363/* 364 * pointer to initial gdt 365 */ 366TEXT tgdtptr(SB),$0 367 WORD $(4*8) 368 LONG $tgdt-KZERO(SB) 369 370/* 371 * Output a string to the display. 372 * String argument is in rSI. 373 */ 374TEXT biosputs(SB), $0 375 PUSHA 376 CLR(rBX) 377_BIOSputs: 378 LODSB 379 ORB(rAL, rAL) 380 JEQ _BIOSputsret 381 382 LBI(0x0E, rAH) 383 BIOSCALL(0x10) 384 JMP _BIOSputs 385 386_BIOSputsret: 387 POPA 388 RET 389 390/* 391 * input a byte 392 */ 393TEXT inb(SB),$0 394 395 MOVL p+0(FP),DX 396 XORL AX,AX 397 INB 398 RET 399 400/* 401 * input a short from a port 402 */ 403TEXT ins(SB), $0 404 405 MOVL p+0(FP), DX 406 XORL AX, AX 407 OPSIZE; INL 408 RET 409 410/* 411 * input a long from a port 412 */ 413TEXT inl(SB), $0 414 415 MOVL p+0(FP), DX 416 XORL AX, AX 417 INL 418 RET 419 420/* 421 * output a byte 422 */ 423TEXT outb(SB),$0 424 425 MOVL p+0(FP),DX 426 MOVL b+4(FP),AX 427 OUTB 428 RET 429 430/* 431 * output a short to a port 432 */ 433TEXT outs(SB), $0 434 MOVL p+0(FP), DX 435 MOVL s+4(FP), AX 436 OPSIZE; OUTL 437 RET 438 439/* 440 * output a long to a port 441 */ 442TEXT outl(SB), $0 443 MOVL p+0(FP), DX 444 MOVL s+4(FP), AX 445 OUTL 446 RET 447 448/* 449 * input a string of bytes from a port 450 */ 451TEXT insb(SB),$0 452 453 MOVL p+0(FP),DX 454 MOVL a+4(FP),DI 455 MOVL c+8(FP),CX 456 CLD; REP; INSB 457 RET 458 459/* 460 * input a string of shorts from a port 461 */ 462TEXT inss(SB),$0 463 MOVL p+0(FP),DX 464 MOVL a+4(FP),DI 465 MOVL c+8(FP),CX 466 CLD 467 REP; OPSIZE; INSL 468 RET 469 470/* 471 * output a string of bytes to a port 472 */ 473TEXT outsb(SB),$0 474 475 MOVL p+0(FP),DX 476 MOVL a+4(FP),SI 477 MOVL c+8(FP),CX 478 CLD; REP; OUTSB 479 RET 480 481/* 482 * output a string of shorts to a port 483 */ 484TEXT outss(SB),$0 485 MOVL p+0(FP),DX 486 MOVL a+4(FP),SI 487 MOVL c+8(FP),CX 488 CLD 489 REP; OPSIZE; OUTSL 490 RET 491 492/* 493 * input a string of longs from a port 494 */ 495TEXT insl(SB),$0 496 497 MOVL p+0(FP),DX 498 MOVL a+4(FP),DI 499 MOVL c+8(FP),CX 500 CLD; REP; INSL 501 RET 502 503/* 504 * output a string of longs to a port 505 */ 506TEXT outsl(SB),$0 507 508 MOVL p+0(FP),DX 509 MOVL a+4(FP),SI 510 MOVL c+8(FP),CX 511 CLD; REP; OUTSL 512 RET 513 514/* 515 * routines to load/read various system registers 516 */ 517GLOBL idtptr(SB),$6 518TEXT putidt(SB),$0 /* interrupt descriptor table */ 519 MOVL t+0(FP),AX 520 MOVL AX,idtptr+2(SB) 521 MOVL l+4(FP),AX 522 MOVW AX,idtptr(SB) 523 MOVL idtptr(SB),IDTR 524 RET 525 526TEXT putcr3(SB),$0 /* top level page table pointer */ 527 MOVL t+0(FP),AX 528 MOVL AX,CR3 529 RET 530 531TEXT getcr0(SB),$0 /* coprocessor bits */ 532 MOVL CR0,AX 533 RET 534 535TEXT getcr2(SB),$0 /* fault address */ 536 MOVL CR2,AX 537 RET 538 539TEXT getcr3(SB),$0 /* page directory base */ 540 MOVL CR3,AX 541 RET 542 543TEXT getcr4(SB), $0 /* CR4 - extensions */ 544 MOVL CR4, AX 545 RET 546 547TEXT _cycles(SB), $0 /* time stamp counter */ 548 RDTSC 549 MOVL vlong+0(FP), CX /* &vlong */ 550 MOVL AX, 0(CX) /* lo */ 551 MOVL DX, 4(CX) /* hi */ 552 RET 553 554TEXT rdmsr(SB), $0 /* model-specific register */ 555 MOVL index+0(FP), CX 556 RDMSR 557 MOVL vlong+4(FP), CX /* &vlong */ 558 MOVL AX, 0(CX) /* lo */ 559 MOVL DX, 4(CX) /* hi */ 560 RET 561 562TEXT wrmsr(SB), $0 563 MOVL index+0(FP), CX 564 MOVL lo+4(FP), AX 565 MOVL hi+8(FP), DX 566 WRMSR 567 RET 568 569TEXT mb386(SB), $0 570 POPL AX /* return PC */ 571 PUSHFL 572 PUSHL CS 573 PUSHL AX 574 IRETL 575 576/* 577 * special traps 578 */ 579TEXT intr0(SB),$0 580 PUSHL $0 581 PUSHL $0 582 JMP intrcommon 583TEXT intr1(SB),$0 584 PUSHL $0 585 PUSHL $1 586 JMP intrcommon 587TEXT intr2(SB),$0 588 PUSHL $0 589 PUSHL $2 590 JMP intrcommon 591TEXT intr3(SB),$0 592 PUSHL $0 593 PUSHL $3 594 JMP intrcommon 595TEXT intr4(SB),$0 596 PUSHL $0 597 PUSHL $4 598 JMP intrcommon 599TEXT intr5(SB),$0 600 PUSHL $0 601 PUSHL $5 602 JMP intrcommon 603TEXT intr6(SB),$0 604 PUSHL $0 605 PUSHL $6 606 JMP intrcommon 607TEXT intr7(SB),$0 608 PUSHL $0 609 PUSHL $7 610 JMP intrcommon 611TEXT intr8(SB),$0 612 PUSHL $8 613 JMP intrcommon 614TEXT intr9(SB),$0 615 PUSHL $0 616 PUSHL $9 617 JMP intrcommon 618TEXT intr10(SB),$0 619 PUSHL $10 620 JMP intrcommon 621TEXT intr11(SB),$0 622 PUSHL $11 623 JMP intrcommon 624TEXT intr12(SB),$0 625 PUSHL $12 626 JMP intrcommon 627TEXT intr13(SB),$0 628 PUSHL $13 629 JMP intrcommon 630TEXT intr14(SB),$0 631 PUSHL $14 632 JMP intrcommon 633TEXT intr15(SB),$0 634 PUSHL $0 635 PUSHL $15 636 JMP intrcommon 637TEXT intr16(SB),$0 638 PUSHL $0 639 PUSHL $16 640 JMP intrcommon 641TEXT intr24(SB),$0 642 PUSHL $0 643 PUSHL $24 644 JMP intrcommon 645TEXT intr25(SB),$0 646 PUSHL $0 647 PUSHL $25 648 JMP intrcommon 649TEXT intr26(SB),$0 650 PUSHL $0 651 PUSHL $26 652 JMP intrcommon 653TEXT intr27(SB),$0 654 PUSHL $0 655 PUSHL $27 656 JMP intrcommon 657TEXT intr28(SB),$0 658 PUSHL $0 659 PUSHL $28 660 JMP intrcommon 661TEXT intr29(SB),$0 662 PUSHL $0 663 PUSHL $29 664 JMP intrcommon 665TEXT intr30(SB),$0 666 PUSHL $0 667 PUSHL $30 668 JMP intrcommon 669TEXT intr31(SB),$0 670 PUSHL $0 671 PUSHL $31 672 JMP intrcommon 673TEXT intr32(SB),$0 674 PUSHL $0 675 PUSHL $32 676 JMP intrcommon 677TEXT intr33(SB),$0 678 PUSHL $0 679 PUSHL $33 680 JMP intrcommon 681TEXT intr34(SB),$0 682 PUSHL $0 683 PUSHL $34 684 JMP intrcommon 685TEXT intr35(SB),$0 686 PUSHL $0 687 PUSHL $35 688 JMP intrcommon 689TEXT intr36(SB),$0 690 PUSHL $0 691 PUSHL $36 692 JMP intrcommon 693TEXT intr37(SB),$0 694 PUSHL $0 695 PUSHL $37 696 JMP intrcommon 697TEXT intr38(SB),$0 698 PUSHL $0 699 PUSHL $38 700 JMP intrcommon 701TEXT intr39(SB),$0 702 PUSHL $0 703 PUSHL $39 704 JMP intrcommon 705TEXT intr64(SB),$0 706 PUSHL $0 707 PUSHL $64 708 JMP intrcommon 709TEXT intrbad(SB),$0 710 PUSHL $0 711 PUSHL $0x1ff 712 JMP intrcommon 713 714intrcommon: 715 PUSHL DS 716 PUSHL ES 717 PUSHL FS 718 PUSHL GS 719 PUSHAL 720 MOVL $(KDSEL),AX 721 MOVW AX,DS 722 MOVW AX,ES 723 LEAL 0(SP),AX 724 PUSHL AX 725 CALL trap(SB) 726 POPL AX 727 POPAL 728 POPL GS 729 POPL FS 730 POPL ES 731 POPL DS 732 ADDL $8,SP /* error code and trap type */ 733 IRETL 734 735 736/* 737 * interrupt level is interrupts on or off 738 */ 739TEXT spllo(SB),$0 740 PUSHFL 741 POPL AX 742 STI 743 RET 744 745TEXT splhi(SB),$0 746 PUSHFL 747 POPL AX 748 CLI 749 RET 750 751TEXT splx(SB),$0 752 MOVL s+0(FP),AX 753 PUSHL AX 754 POPFL 755 RET 756 757/* 758 * do nothing whatsoever till interrupt happens 759 */ 760TEXT idle(SB),$0 761 HLT 762 RET 763 764/* 765 * Try to determine the CPU type which requires fiddling with EFLAGS. 766 * If the Id bit can be toggled then the CPUID instruciton can be used 767 * to determine CPU identity and features. First have to check if it's 768 * a 386 (Ac bit can't be set). If it's not a 386 and the Id bit can't be 769 * toggled then it's an older 486 of some kind. 770 * 771 * cpuid(id[], &ax, &dx); 772 */ 773#define CPUID BYTE $0x0F; BYTE $0xA2 /* CPUID, argument in AX */ 774TEXT cpuid(SB), $0 775 MOVL $0x240000, AX 776 PUSHL AX 777 POPFL /* set Id|Ac */ 778 779 PUSHFL 780 POPL BX /* retrieve value */ 781 782 MOVL $0, AX 783 PUSHL AX 784 POPFL /* clear Id|Ac, EFLAGS initialised */ 785 786 PUSHFL 787 POPL AX /* retrieve value */ 788 XORL BX, AX 789 TESTL $0x040000, AX /* Ac */ 790 JZ _cpu386 /* can't set this bit on 386 */ 791 TESTL $0x200000, AX /* Id */ 792 JZ _cpu486 /* can't toggle this bit on some 486 */ 793 794 MOVL $0, AX 795 CPUID 796 MOVL id+0(FP), BP 797 MOVL BX, 0(BP) /* "Genu" "Auth" "Cyri" */ 798 MOVL DX, 4(BP) /* "ineI" "enti" "xIns" */ 799 MOVL CX, 8(BP) /* "ntel" "cAMD" "tead" */ 800 801 MOVL $1, AX 802 CPUID 803 JMP _cpuid 804 805_cpu486: 806 MOVL $0x400, AX 807 MOVL $0, DX 808 JMP _cpuid 809 810_cpu386: 811 MOVL $0x300, AX 812 MOVL $0, DX 813 814_cpuid: 815 MOVL ax+4(FP), BP 816 MOVL AX, 0(BP) 817 MOVL dx+8(FP), BP 818 MOVL DX, 0(BP) 819 RET 820 821 822/* 823 * basic timing loop to determine CPU frequency 824 */ 825TEXT aamloop(SB),$0 826 827 MOVL c+0(FP),CX 828aaml1: 829 AAM 830 LOOP aaml1 831 RET 832 833TEXT hello(SB), $0 834 BYTE $'P'; BYTE $'l'; BYTE $'a'; BYTE $'n'; 835 BYTE $' '; BYTE $'9'; BYTE $' '; BYTE $'f'; 836 BYTE $'r'; BYTE $'o'; BYTE $'m'; BYTE $' '; 837 BYTE $'B'; BYTE $'e'; BYTE $'l'; BYTE $'l'; 838 BYTE $' '; BYTE $'L'; BYTE $'a'; BYTE $'b'; 839 BYTE $'s'; 840#ifdef PXE 841 BYTE $' '; BYTE $'b'; BYTE $'y'; BYTE $' '; 842 BYTE $'P'; BYTE $'X'; BYTE $'E'; 843#endif 844 BYTE $'\r'; 845 BYTE $'\n'; 846 BYTE $'\z'; 847 848TEXT rock(SB), $0 849 BYTE $0; BYTE $0; BYTE $0; BYTE $0; 850 851GLOBL pxe(SB), $4 852#ifdef PXE 853DATA pxe+0(SB)/4, $1 854#else 855DATA pxe+0(SB)/4, $0 856#endif /* PXE */ 857 858/* 859 * Save registers. 860 */ 861TEXT saveregs(SB), $0 862 /* appease 8l */ 863 SUBL $32, SP 864 POPL AX 865 POPL AX 866 POPL AX 867 POPL AX 868 POPL AX 869 POPL AX 870 POPL AX 871 POPL AX 872 873 PUSHL AX 874 PUSHL BX 875 PUSHL CX 876 PUSHL DX 877 PUSHL BP 878 PUSHL DI 879 PUSHL SI 880 PUSHFL 881 882 XCHGL 32(SP), AX /* swap return PC and saved flags */ 883 XCHGL 0(SP), AX 884 XCHGL 32(SP), AX 885 RET 886 887TEXT restoreregs(SB), $0 888 /* appease 8l */ 889 PUSHL AX 890 PUSHL AX 891 PUSHL AX 892 PUSHL AX 893 PUSHL AX 894 PUSHL AX 895 PUSHL AX 896 PUSHL AX 897 ADDL $32, SP 898 899 XCHGL 32(SP), AX /* swap return PC and saved flags */ 900 XCHGL 0(SP), AX 901 XCHGL 32(SP), AX 902 903 POPFL 904 POPL SI 905 POPL DI 906 POPL BP 907 POPL DX 908 POPL CX 909 POPL BX 910 POPL AX 911 RET 912 913/* 914 * Assumed to be in protected mode at time of call. 915 * Switch to real mode, execute an interrupt, and 916 * then switch back to protected mode. 917 * 918 * Assumes: 919 * 920 * - no device interrupts are going to come in 921 * - 0-16MB is identity mapped in page tables 922 * - can use code segment 0x1000 in real mode 923 * to get at l.s code 924 */ 925TEXT realmodeidtptr(SB), $0 926 WORD $(4*256-1) 927 LONG $0 928 929TEXT realmode0(SB), $0 930 CALL saveregs(SB) 931 932 /* switch to low code address */ 933 LEAL physcode-KZERO(SB), AX 934 JMP *AX 935 936TEXT physcode(SB), $0 937 938 /* switch to low stack */ 939 MOVL SP, AX 940 MOVL $0x7C00, SP 941 PUSHL AX 942 943 /* load IDT with real-mode version; GDT already fine */ 944 MOVL realmodeidtptr(SB), IDTR 945 946 /* edit INT $0x00 instruction below */ 947 MOVL realmodeintr(SB), AX 948 MOVB AX, realmodeintrinst+1(SB) 949 950 /* disable paging */ 951 MOVL CR0, AX 952 ANDL $0x7FFFFFFF, AX 953 MOVL AX, CR0 954 /* JMP .+2 to clear prefetch queue*/ 955 BYTE $0xEB; BYTE $0x00 956 957 /* jump to 16-bit code segment */ 958/* JMPFAR SELECTOR(3, SELGDT, 0):$again16bit(SB) /**/ 959 BYTE $0xEA 960 LONG $again16bit-KZERO(SB) 961 WORD $SELECTOR(3, SELGDT, 0) 962 963TEXT again16bit(SB), $0 964 /* 965 * Now in 16-bit compatibility mode. 966 * These are 32-bit instructions being interpreted 967 * as 16-bit instructions. I'm being lazy and 968 * not using the macros because I know when 969 * the 16- and 32-bit instructions look the same 970 * or close enough. 971 */ 972 973 /* disable protected mode and jump to real mode cs */ 974 OPSIZE; MOVL CR0, AX 975 OPSIZE; XORL BX, BX 976 OPSIZE; INCL BX 977 OPSIZE; XORL BX, AX 978 OPSIZE; MOVL AX, CR0 979 980 /* JMPFAR 0x1000:now16real */ 981 BYTE $0xEA 982 WORD $now16real-KZERO(SB) 983 WORD $0x1000 984 985TEXT now16real(SB), $0 986 /* copy the registers for the bios call */ 987 LWI(0x1000, rAX) 988 MOVW AX,SS 989 LWI(realmoderegs(SB), rBP) 990 991 /* offsets are in Ureg */ 992 LXW(44, xBP, rAX) 993 MOVW AX, DS 994 LXW(40, xBP, rAX) 995 MOVW AX, ES 996 997 OPSIZE; LXW(0, xBP, rDI) 998 OPSIZE; LXW(4, xBP, rSI) 999 OPSIZE; LXW(16, xBP, rBX) 1000 OPSIZE; LXW(20, xBP, rDX) 1001 OPSIZE; LXW(24, xBP, rCX) 1002 OPSIZE; LXW(28, xBP, rAX) 1003 1004 CLC 1005 1006TEXT realmodeintrinst(SB), $0 1007 INT $0x00 1008 1009 1010 /* save the registers after the call */ 1011 1012 LWI(0x7bfc, rSP) 1013 OPSIZE; PUSHFL 1014 OPSIZE; PUSHL AX 1015 1016 LWI(0x1000, rAX) 1017 MOVW AX,SS 1018 LWI(realmoderegs(SB), rBP) 1019 1020 OPSIZE; SXW(rDI, 0, xBP) 1021 OPSIZE; SXW(rSI, 4, xBP) 1022 OPSIZE; SXW(rBX, 16, xBP) 1023 OPSIZE; SXW(rDX, 20, xBP) 1024 OPSIZE; SXW(rCX, 24, xBP) 1025 OPSIZE; POPL AX 1026 OPSIZE; SXW(rAX, 28, xBP) 1027 1028 MOVW DS, AX 1029 OPSIZE; SXW(rAX, 44, xBP) 1030 MOVW ES, AX 1031 OPSIZE; SXW(rAX, 40, xBP) 1032 1033 OPSIZE; POPL AX 1034 OPSIZE; SXW(rAX, 64, xBP) /* flags */ 1035 1036 /* re-enter protected mode and jump to 32-bit code */ 1037 OPSIZE; MOVL $1, AX 1038 OPSIZE; MOVL AX, CR0 1039 1040/* JMPFAR SELECTOR(2, SELGDT, 0):$again32bit(SB) /**/ 1041 OPSIZE 1042 BYTE $0xEA 1043 LONG $again32bit-KZERO(SB) 1044 WORD $SELECTOR(2, SELGDT, 0) 1045 1046TEXT again32bit(SB), $0 1047 MOVW $SELECTOR(1, SELGDT, 0),AX 1048 MOVW AX,DS 1049 MOVW AX,SS 1050 MOVW AX,ES 1051 MOVW AX,FS 1052 MOVW AX,GS 1053 1054 /* enable paging and jump to kzero-address code */ 1055 MOVL CR0, AX 1056 ORL $0x80000000, AX 1057 MOVL AX, CR0 1058 LEAL again32kzero(SB), AX 1059 JMP* AX 1060 1061TEXT again32kzero(SB), $0 1062 /* breathe a sigh of relief - back in 32-bit protected mode */ 1063 1064 /* switch to old stack */ 1065 PUSHL AX /* match popl below for 8l */ 1066 MOVL $0x7BFC, SP 1067 POPL SP 1068 1069 /* restore idt */ 1070 MOVL idtptr(SB),IDTR 1071 1072 CALL restoreregs(SB) 1073 RET 1074 1075TEXT realmoderegs(SB), $0 1076 LONG $0; LONG $0; LONG $0; LONG $0 1077 LONG $0; LONG $0; LONG $0; LONG $0 1078 LONG $0; LONG $0; LONG $0; LONG $0 1079 LONG $0; LONG $0; LONG $0; LONG $0 1080 LONG $0; LONG $0; LONG $0; LONG $0 1081 1082TEXT realmodeintr(SB), $0 1083 LONG $0 1084 1085