locore.s revision 131814
1/*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * William Jolitz. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * from: @(#)locore.s 7.3 (Berkeley) 5/13/91 33 * $FreeBSD: head/sys/i386/i386/locore.s 131814 2004-07-08 13:40:33Z brian $ 34 * 35 * originally from: locore.s, by William F. Jolitz 36 * 37 * Substantially rewritten by David Greenman, Rod Grimes, 38 * Bruce Evans, Wolfgang Solfrank, Poul-Henning Kamp 39 * and many others. 40 */ 41 42#include "opt_compat.h" 43#include "opt_nfsroot.h" 44#include "opt_pmap.h" 45 46#include <sys/syscall.h> 47#include <sys/reboot.h> 48 49#include <machine/asmacros.h> 50#include <machine/cputypes.h> 51#include <machine/psl.h> 52#include <machine/pmap.h> 53#include <machine/specialreg.h> 54 55#include "assym.s" 56 57/* 58 * XXX 59 * 60 * Note: This version greatly munged to avoid various assembler errors 61 * that may be fixed in newer versions of gas. Perhaps newer versions 62 * will have more pleasant appearance. 63 */ 64 65/* 66 * PTmap is recursive pagemap at top of virtual address space. 67 * Within PTmap, the page directory can be found (third indirection). 68 */ 69 .globl PTmap,PTD,PTDpde 70 .set PTmap,(PTDPTDI << PDRSHIFT) 71 .set PTD,PTmap + (PTDPTDI * PAGE_SIZE) 72 .set PTDpde,PTD + (PTDPTDI * PDESIZE) 73 74#ifdef SMP 75/* 76 * Define layout of per-cpu address space. 77 * This is "constructed" in locore.s on the BSP and in mp_machdep.c 78 * for each AP. DO NOT REORDER THESE WITHOUT UPDATING THE REST! 79 */ 80 .globl SMP_prvspace 81 .set SMP_prvspace,(MPPTDI << PDRSHIFT) 82#endif /* SMP */ 83 84/* 85 * Compiled KERNBASE location and the kernel load address 86 */ 87 .globl kernbase 88 .set kernbase,KERNBASE 89 .globl kernload 90 .set kernload,KERNLOAD 91 92/* 93 * Globals 94 */ 95 .data 96 ALIGN_DATA /* just to be sure */ 97 98 .space 0x2000 /* space for tmpstk - temporary stack */ 99tmpstk: 100 101 .globl bootinfo 102bootinfo: .space BOOTINFO_SIZE /* bootinfo that we can handle */ 103 104 .globl KERNend 105KERNend: .long 0 /* phys addr end of kernel (just after bss) */ 106physfree: .long 0 /* phys addr of next free page */ 107 108#ifdef SMP 109 .globl cpu0prvpage 110cpu0pp: .long 0 /* phys addr cpu0 private pg */ 111cpu0prvpage: .long 0 /* relocated version */ 112 113 .globl SMPpt 114SMPptpa: .long 0 /* phys addr SMP page table */ 115SMPpt: .long 0 /* relocated version */ 116#endif /* SMP */ 117 118 .globl IdlePTD 119IdlePTD: .long 0 /* phys addr of kernel PTD */ 120 121#ifdef PAE 122 .globl IdlePDPT 123IdlePDPT: .long 0 /* phys addr of kernel PDPT */ 124#endif 125 126#ifdef SMP 127 .globl KPTphys 128#endif 129KPTphys: .long 0 /* phys addr of kernel page tables */ 130 131 .globl proc0uarea, proc0kstack 132proc0uarea: .long 0 /* address of proc 0 uarea space */ 133proc0kstack: .long 0 /* address of proc 0 kstack space */ 134p0upa: .long 0 /* phys addr of proc0's UAREA */ 135p0kpa: .long 0 /* phys addr of proc0's STACK */ 136 137vm86phystk: .long 0 /* PA of vm86/bios stack */ 138 139 .globl vm86paddr, vm86pa 140vm86paddr: .long 0 /* address of vm86 region */ 141vm86pa: .long 0 /* phys addr of vm86 region */ 142 143#ifdef PC98 144 .globl pc98_system_parameter 145pc98_system_parameter: 146 .space 0x240 147#endif 148 149/********************************************************************** 150 * 151 * Some handy macros 152 * 153 */ 154 155#define R(foo) ((foo)-KERNBASE) 156 157#define ALLOCPAGES(foo) \ 158 movl R(physfree), %esi ; \ 159 movl $((foo)*PAGE_SIZE), %eax ; \ 160 addl %esi, %eax ; \ 161 movl %eax, R(physfree) ; \ 162 movl %esi, %edi ; \ 163 movl $((foo)*PAGE_SIZE),%ecx ; \ 164 xorl %eax,%eax ; \ 165 cld ; \ 166 rep ; \ 167 stosb 168 169/* 170 * fillkpt 171 * eax = page frame address 172 * ebx = index into page table 173 * ecx = how many pages to map 174 * base = base address of page dir/table 175 * prot = protection bits 176 */ 177#define fillkpt(base, prot) \ 178 shll $PTESHIFT,%ebx ; \ 179 addl base,%ebx ; \ 180 orl $PG_V,%eax ; \ 181 orl prot,%eax ; \ 1821: movl %eax,(%ebx) ; \ 183 addl $PAGE_SIZE,%eax ; /* increment physical address */ \ 184 addl $PTESIZE,%ebx ; /* next pte */ \ 185 loop 1b 186 187/* 188 * fillkptphys(prot) 189 * eax = physical address 190 * ecx = how many pages to map 191 * prot = protection bits 192 */ 193#define fillkptphys(prot) \ 194 movl %eax, %ebx ; \ 195 shrl $PAGE_SHIFT, %ebx ; \ 196 fillkpt(R(KPTphys), prot) 197 198 .text 199/********************************************************************** 200 * 201 * This is where the bootblocks start us, set the ball rolling... 202 * 203 */ 204NON_GPROF_ENTRY(btext) 205 206#ifdef PC98 207 /* save SYSTEM PARAMETER for resume (NS/T or other) */ 208 movl $0xa1400,%esi 209 movl $R(pc98_system_parameter),%edi 210 movl $0x0240,%ecx 211 cld 212 rep 213 movsb 214#else /* IBM-PC */ 215/* Tell the bios to warmboot next time */ 216 movw $0x1234,0x472 217#endif /* PC98 */ 218 219/* Set up a real frame in case the double return in newboot is executed. */ 220 pushl %ebp 221 movl %esp, %ebp 222 223/* Don't trust what the BIOS gives for eflags. */ 224 pushl $PSL_KERNEL 225 popfl 226 227/* 228 * Don't trust what the BIOS gives for %fs and %gs. Trust the bootstrap 229 * to set %cs, %ds, %es and %ss. 230 */ 231 mov %ds, %ax 232 mov %ax, %fs 233 mov %ax, %gs 234 235/* 236 * Clear the bss. Not all boot programs do it, and it is our job anyway. 237 * 238 * XXX we don't check that there is memory for our bss and page tables 239 * before using it. 240 * 241 * Note: we must be careful to not overwrite an active gdt or idt. They 242 * inactive from now until we switch to new ones, since we don't load any 243 * more segment registers or permit interrupts until after the switch. 244 */ 245 movl $R(end),%ecx 246 movl $R(edata),%edi 247 subl %edi,%ecx 248 xorl %eax,%eax 249 cld 250 rep 251 stosb 252 253 call recover_bootinfo 254 255/* Get onto a stack that we can trust. */ 256/* 257 * XXX this step is delayed in case recover_bootinfo needs to return via 258 * the old stack, but it need not be, since recover_bootinfo actually 259 * returns via the old frame. 260 */ 261 movl $R(tmpstk),%esp 262 263#ifdef PC98 264 /* pc98_machine_type & M_EPSON_PC98 */ 265 testb $0x02,R(pc98_system_parameter)+220 266 jz 3f 267 /* epson_machine_id <= 0x0b */ 268 cmpb $0x0b,R(pc98_system_parameter)+224 269 ja 3f 270 271 /* count up memory */ 272 movl $0x100000,%eax /* next, talley remaining memory */ 273 movl $0xFFF-0x100,%ecx 2741: movl 0(%eax),%ebx /* save location to check */ 275 movl $0xa55a5aa5,0(%eax) /* write test pattern */ 276 cmpl $0xa55a5aa5,0(%eax) /* does not check yet for rollover */ 277 jne 2f 278 movl %ebx,0(%eax) /* restore memory */ 279 addl $PAGE_SIZE,%eax 280 loop 1b 2812: subl $0x100000,%eax 282 shrl $17,%eax 283 movb %al,R(pc98_system_parameter)+1 2843: 285 286 movw R(pc98_system_parameter+0x86),%ax 287 movw %ax,R(cpu_id) 288#endif 289 290 call identify_cpu 291 call create_pagetables 292 293/* 294 * If the CPU has support for VME, turn it on. 295 */ 296 testl $CPUID_VME, R(cpu_feature) 297 jz 1f 298 movl %cr4, %eax 299 orl $CR4_VME, %eax 300 movl %eax, %cr4 3011: 302 303/* Now enable paging */ 304#ifdef PAE 305 movl R(IdlePDPT), %eax 306 movl %eax, %cr3 307 movl %cr4, %eax 308 orl $CR4_PAE, %eax 309 movl %eax, %cr4 310#else 311 movl R(IdlePTD), %eax 312 movl %eax,%cr3 /* load ptd addr into mmu */ 313#endif 314 movl %cr0,%eax /* get control word */ 315 orl $CR0_PE|CR0_PG,%eax /* enable paging */ 316 movl %eax,%cr0 /* and let's page NOW! */ 317 318 pushl $begin /* jump to high virtualized address */ 319 ret 320 321/* now running relocated at KERNBASE where the system is linked to run */ 322begin: 323 /* set up bootstrap stack */ 324 movl proc0kstack,%eax /* location of in-kernel stack */ 325 /* bootstrap stack end location */ 326 leal (KSTACK_PAGES*PAGE_SIZE-PCB_SIZE)(%eax),%esp 327 328 xorl %ebp,%ebp /* mark end of frames */ 329 330#ifdef PAE 331 movl IdlePDPT,%esi 332#else 333 movl IdlePTD,%esi 334#endif 335 movl %esi,(KSTACK_PAGES*PAGE_SIZE-PCB_SIZE+PCB_CR3)(%eax) 336 337 pushl physfree /* value of first for init386(first) */ 338 call init386 /* wire 386 chip for unix operation */ 339 340 /* 341 * Clean up the stack in a way that db_numargs() understands, so 342 * that backtraces in ddb don't underrun the stack. Traps for 343 * inaccessible memory are more fatal than usual this early. 344 */ 345 addl $4,%esp 346 347 call mi_startup /* autoconfiguration, mountroot etc */ 348 /* NOTREACHED */ 349 addl $0,%esp /* for db_numargs() again */ 350 351/* 352 * Signal trampoline, copied to top of user stack 353 */ 354NON_GPROF_ENTRY(sigcode) 355 calll *SIGF_HANDLER(%esp) 356 leal SIGF_UC(%esp),%eax /* get ucontext */ 357 pushl %eax 358 testl $PSL_VM,UC_EFLAGS(%eax) 359 jne 1f 360 movl UC_GS(%eax),%gs /* restore %gs */ 3611: 362 movl $SYS_sigreturn,%eax 363 pushl %eax /* junk to fake return addr. */ 364 int $0x80 /* enter kernel with args */ 365 /* on stack */ 3661: 367 jmp 1b 368 369#ifdef COMPAT_FREEBSD4 370 ALIGN_TEXT 371freebsd4_sigcode: 372 calll *SIGF_HANDLER(%esp) 373 leal SIGF_UC4(%esp),%eax /* get ucontext */ 374 pushl %eax 375 testl $PSL_VM,UC4_EFLAGS(%eax) 376 jne 1f 377 movl UC4_GS(%eax),%gs /* restore %gs */ 3781: 379 movl $344,%eax /* 4.x SYS_sigreturn */ 380 pushl %eax /* junk to fake return addr. */ 381 int $0x80 /* enter kernel with args */ 382 /* on stack */ 3831: 384 jmp 1b 385#endif 386 387#ifdef COMPAT_43 388 ALIGN_TEXT 389osigcode: 390 call *SIGF_HANDLER(%esp) /* call signal handler */ 391 lea SIGF_SC(%esp),%eax /* get sigcontext */ 392 pushl %eax 393 testl $PSL_VM,SC_PS(%eax) 394 jne 9f 395 movl SC_GS(%eax),%gs /* restore %gs */ 3969: 397 movl $103,%eax /* 3.x SYS_sigreturn */ 398 pushl %eax /* junk to fake return addr. */ 399 int $0x80 /* enter kernel with args */ 4000: jmp 0b 401#endif /* COMPAT_43 */ 402 403 ALIGN_TEXT 404esigcode: 405 406 .data 407 .globl szsigcode 408szsigcode: 409 .long esigcode-sigcode 410#ifdef COMPAT_FREEBSD4 411 .globl szfreebsd4_sigcode 412szfreebsd4_sigcode: 413 .long esigcode-freebsd4_sigcode 414#endif 415#ifdef COMPAT_43 416 .globl szosigcode 417szosigcode: 418 .long esigcode-osigcode 419#endif 420 .text 421 422/********************************************************************** 423 * 424 * Recover the bootinfo passed to us from the boot program 425 * 426 */ 427recover_bootinfo: 428 /* 429 * This code is called in different ways depending on what loaded 430 * and started the kernel. This is used to detect how we get the 431 * arguments from the other code and what we do with them. 432 * 433 * Old disk boot blocks: 434 * (*btext)(howto, bootdev, cyloffset, esym); 435 * [return address == 0, and can NOT be returned to] 436 * [cyloffset was not supported by the FreeBSD boot code 437 * and always passed in as 0] 438 * [esym is also known as total in the boot code, and 439 * was never properly supported by the FreeBSD boot code] 440 * 441 * Old diskless netboot code: 442 * (*btext)(0,0,0,0,&nfsdiskless,0,0,0); 443 * [return address != 0, and can NOT be returned to] 444 * If we are being booted by this code it will NOT work, 445 * so we are just going to halt if we find this case. 446 * 447 * New uniform boot code: 448 * (*btext)(howto, bootdev, 0, 0, 0, &bootinfo) 449 * [return address != 0, and can be returned to] 450 * 451 * There may seem to be a lot of wasted arguments in here, but 452 * that is so the newer boot code can still load very old kernels 453 * and old boot code can load new kernels. 454 */ 455 456 /* 457 * The old style disk boot blocks fake a frame on the stack and 458 * did an lret to get here. The frame on the stack has a return 459 * address of 0. 460 */ 461 cmpl $0,4(%ebp) 462 je olddiskboot 463 464 /* 465 * We have some form of return address, so this is either the 466 * old diskless netboot code, or the new uniform code. That can 467 * be detected by looking at the 5th argument, if it is 0 468 * we are being booted by the new uniform boot code. 469 */ 470 cmpl $0,24(%ebp) 471 je newboot 472 473 /* 474 * Seems we have been loaded by the old diskless boot code, we 475 * don't stand a chance of running as the diskless structure 476 * changed considerably between the two, so just halt. 477 */ 478 hlt 479 480 /* 481 * We have been loaded by the new uniform boot code. 482 * Let's check the bootinfo version, and if we do not understand 483 * it we return to the loader with a status of 1 to indicate this error 484 */ 485newboot: 486 movl 28(%ebp),%ebx /* &bootinfo.version */ 487 movl BI_VERSION(%ebx),%eax 488 cmpl $1,%eax /* We only understand version 1 */ 489 je 1f 490 movl $1,%eax /* Return status */ 491 leave 492 /* 493 * XXX this returns to our caller's caller (as is required) since 494 * we didn't set up a frame and our caller did. 495 */ 496 ret 497 4981: 499 /* 500 * If we have a kernelname copy it in 501 */ 502 movl BI_KERNELNAME(%ebx),%esi 503 cmpl $0,%esi 504 je 2f /* No kernelname */ 505 movl $MAXPATHLEN,%ecx /* Brute force!!! */ 506 movl $R(kernelname),%edi 507 cmpb $'/',(%esi) /* Make sure it starts with a slash */ 508 je 1f 509 movb $'/',(%edi) 510 incl %edi 511 decl %ecx 5121: 513 cld 514 rep 515 movsb 516 5172: 518 /* 519 * Determine the size of the boot loader's copy of the bootinfo 520 * struct. This is impossible to do properly because old versions 521 * of the struct don't contain a size field and there are 2 old 522 * versions with the same version number. 523 */ 524 movl $BI_ENDCOMMON,%ecx /* prepare for sizeless version */ 525 testl $RB_BOOTINFO,8(%ebp) /* bi_size (and bootinfo) valid? */ 526 je got_bi_size /* no, sizeless version */ 527 movl BI_SIZE(%ebx),%ecx 528got_bi_size: 529 530 /* 531 * Copy the common part of the bootinfo struct 532 */ 533 movl %ebx,%esi 534 movl $R(bootinfo),%edi 535 cmpl $BOOTINFO_SIZE,%ecx 536 jbe got_common_bi_size 537 movl $BOOTINFO_SIZE,%ecx 538got_common_bi_size: 539 cld 540 rep 541 movsb 542 543#ifdef NFS_ROOT 544 /* 545 * If we have a nfs_diskless structure copy it in 546 */ 547 movl BI_NFS_DISKLESS(%ebx),%esi 548 cmpl $0,%esi 549 je olddiskboot 550 movl $R(nfs_diskless),%edi 551 movl $NFSDISKLESS_SIZE,%ecx 552 cld 553 rep 554 movsb 555 movl $R(nfs_diskless_valid),%edi 556 movl $1,(%edi) 557#endif 558 559 /* 560 * The old style disk boot. 561 * (*btext)(howto, bootdev, cyloffset, esym); 562 * Note that the newer boot code just falls into here to pick 563 * up howto and bootdev, cyloffset and esym are no longer used 564 */ 565olddiskboot: 566 movl 8(%ebp),%eax 567 movl %eax,R(boothowto) 568 movl 12(%ebp),%eax 569 movl %eax,R(bootdev) 570 571 ret 572 573 574/********************************************************************** 575 * 576 * Identify the CPU and initialize anything special about it 577 * 578 */ 579identify_cpu: 580 581 /* Try to toggle alignment check flag; does not exist on 386. */ 582 pushfl 583 popl %eax 584 movl %eax,%ecx 585 orl $PSL_AC,%eax 586 pushl %eax 587 popfl 588 pushfl 589 popl %eax 590 xorl %ecx,%eax 591 andl $PSL_AC,%eax 592 pushl %ecx 593 popfl 594 595 testl %eax,%eax 596 jnz try486 597 598 /* NexGen CPU does not have aligment check flag. */ 599 pushfl 600 movl $0x5555, %eax 601 xorl %edx, %edx 602 movl $2, %ecx 603 clc 604 divl %ecx 605 jz trynexgen 606 popfl 607 movl $CPU_386,R(cpu) 608 jmp 3f 609 610trynexgen: 611 popfl 612 movl $CPU_NX586,R(cpu) 613 movl $0x4778654e,R(cpu_vendor) # store vendor string 614 movl $0x72446e65,R(cpu_vendor+4) 615 movl $0x6e657669,R(cpu_vendor+8) 616 movl $0,R(cpu_vendor+12) 617 jmp 3f 618 619try486: /* Try to toggle identification flag; does not exist on early 486s. */ 620 pushfl 621 popl %eax 622 movl %eax,%ecx 623 xorl $PSL_ID,%eax 624 pushl %eax 625 popfl 626 pushfl 627 popl %eax 628 xorl %ecx,%eax 629 andl $PSL_ID,%eax 630 pushl %ecx 631 popfl 632 633 testl %eax,%eax 634 jnz trycpuid 635 movl $CPU_486,R(cpu) 636 637 /* 638 * Check Cyrix CPU 639 * Cyrix CPUs do not change the undefined flags following 640 * execution of the divide instruction which divides 5 by 2. 641 * 642 * Note: CPUID is enabled on M2, so it passes another way. 643 */ 644 pushfl 645 movl $0x5555, %eax 646 xorl %edx, %edx 647 movl $2, %ecx 648 clc 649 divl %ecx 650 jnc trycyrix 651 popfl 652 jmp 3f /* You may use Intel CPU. */ 653 654trycyrix: 655 popfl 656 /* 657 * IBM Bluelighting CPU also doesn't change the undefined flags. 658 * Because IBM doesn't disclose the information for Bluelighting 659 * CPU, we couldn't distinguish it from Cyrix's (including IBM 660 * brand of Cyrix CPUs). 661 */ 662 movl $0x69727943,R(cpu_vendor) # store vendor string 663 movl $0x736e4978,R(cpu_vendor+4) 664 movl $0x64616574,R(cpu_vendor+8) 665 jmp 3f 666 667trycpuid: /* Use the `cpuid' instruction. */ 668 xorl %eax,%eax 669 cpuid # cpuid 0 670 movl %eax,R(cpu_high) # highest capability 671 movl %ebx,R(cpu_vendor) # store vendor string 672 movl %edx,R(cpu_vendor+4) 673 movl %ecx,R(cpu_vendor+8) 674 movb $0,R(cpu_vendor+12) 675 676 movl $1,%eax 677 cpuid # cpuid 1 678 movl %eax,R(cpu_id) # store cpu_id 679 movl %ebx,R(cpu_procinfo) # store cpu_procinfo 680 movl %edx,R(cpu_feature) # store cpu_feature 681 rorl $8,%eax # extract family type 682 andl $15,%eax 683 cmpl $5,%eax 684 jae 1f 685 686 /* less than Pentium; must be 486 */ 687 movl $CPU_486,R(cpu) 688 jmp 3f 6891: 690 /* a Pentium? */ 691 cmpl $5,%eax 692 jne 2f 693 movl $CPU_586,R(cpu) 694 jmp 3f 6952: 696 /* Greater than Pentium...call it a Pentium Pro */ 697 movl $CPU_686,R(cpu) 6983: 699 ret 700 701 702/********************************************************************** 703 * 704 * Create the first page directory and its page tables. 705 * 706 */ 707 708create_pagetables: 709 710/* Find end of kernel image (rounded up to a page boundary). */ 711 movl $R(_end),%esi 712 713/* Include symbols, if any. */ 714 movl R(bootinfo+BI_ESYMTAB),%edi 715 testl %edi,%edi 716 je over_symalloc 717 movl %edi,%esi 718 movl $KERNBASE,%edi 719 addl %edi,R(bootinfo+BI_SYMTAB) 720 addl %edi,R(bootinfo+BI_ESYMTAB) 721over_symalloc: 722 723/* If we are told where the end of the kernel space is, believe it. */ 724 movl R(bootinfo+BI_KERNEND),%edi 725 testl %edi,%edi 726 je no_kernend 727 movl %edi,%esi 728no_kernend: 729 730 addl $PDRMASK,%esi /* Play conservative for now, and */ 731 andl $~PDRMASK,%esi /* ... wrap to next 4M. */ 732 movl %esi,R(KERNend) /* save end of kernel */ 733 movl %esi,R(physfree) /* next free page is at end of kernel */ 734 735/* Allocate Kernel Page Tables */ 736 ALLOCPAGES(NKPT) 737 movl %esi,R(KPTphys) 738 739/* Allocate Page Table Directory */ 740#ifdef PAE 741 /* XXX only need 32 bytes (easier for now) */ 742 ALLOCPAGES(1) 743 movl %esi,R(IdlePDPT) 744#endif 745 ALLOCPAGES(NPGPTD) 746 movl %esi,R(IdlePTD) 747 748/* Allocate UPAGES */ 749 ALLOCPAGES(UAREA_PAGES) 750 movl %esi,R(p0upa) 751 addl $KERNBASE, %esi 752 movl %esi, R(proc0uarea) 753 754 ALLOCPAGES(KSTACK_PAGES) 755 movl %esi,R(p0kpa) 756 addl $KERNBASE, %esi 757 movl %esi, R(proc0kstack) 758 759 ALLOCPAGES(1) /* vm86/bios stack */ 760 movl %esi,R(vm86phystk) 761 762 ALLOCPAGES(3) /* pgtable + ext + IOPAGES */ 763 movl %esi,R(vm86pa) 764 addl $KERNBASE, %esi 765 movl %esi, R(vm86paddr) 766 767#ifdef SMP 768/* Allocate cpu0's private data page */ 769 ALLOCPAGES(1) 770 movl %esi,R(cpu0pp) 771 addl $KERNBASE, %esi 772 movl %esi, R(cpu0prvpage) /* relocated to KVM space */ 773 774/* Allocate SMP page table page */ 775 ALLOCPAGES(1) 776 movl %esi,R(SMPptpa) 777 addl $KERNBASE, %esi 778 movl %esi, R(SMPpt) /* relocated to KVM space */ 779#endif /* SMP */ 780 781/* Map page zero read-write so bios32 calls can use it */ 782 xorl %eax, %eax 783 movl $PG_RW,%edx 784 movl $1,%ecx 785 fillkptphys(%edx) 786 787/* Map read-only from page 1 to the beginning of the kernel text section */ 788 movl $PAGE_SIZE, %eax 789 xorl %edx,%edx 790 movl $R(btext),%ecx 791 addl $PAGE_MASK,%ecx 792 subl %eax,%ecx 793 shrl $PAGE_SHIFT,%ecx 794 fillkptphys(%edx) 795 796/* 797 * Enable PSE and PGE. 798 */ 799#ifndef DISABLE_PSE 800 testl $CPUID_PSE, R(cpu_feature) 801 jz 1f 802 movl $PG_PS, R(pseflag) 803 movl %cr4, %eax 804 orl $CR4_PSE, %eax 805 movl %eax, %cr4 8061: 807#endif 808#ifndef DISABLE_PG_G 809 testl $CPUID_PGE, R(cpu_feature) 810 jz 2f 811 movl $PG_G, R(pgeflag) 812 movl %cr4, %eax 813 orl $CR4_PGE, %eax 814 movl %eax, %cr4 8152: 816#endif 817 818/* 819 * Write page tables for the kernel starting at btext and 820 * until the end. Make sure to map read+write. We do this even 821 * if we've enabled PSE above, we'll just switch the corresponding kernel 822 * PDEs before we turn on paging. 823 * 824 * XXX: We waste some pages here in the PSE case! DON'T BLINDLY REMOVE 825 * THIS! SMP needs the page table to be there to map the kernel P==V. 826 */ 827 movl $R(btext),%eax 828 addl $PAGE_MASK, %eax 829 andl $~PAGE_MASK, %eax 830 movl $PG_RW,%edx 831 movl R(KERNend),%ecx 832 subl %eax,%ecx 833 shrl $PAGE_SHIFT,%ecx 834 fillkptphys(%edx) 835 836/* Map page directory. */ 837#ifdef PAE 838 movl R(IdlePDPT), %eax 839 movl $1, %ecx 840 fillkptphys($PG_RW) 841#endif 842 843 movl R(IdlePTD), %eax 844 movl $NPGPTD, %ecx 845 fillkptphys($PG_RW) 846 847/* Map proc0's UPAGES in the physical way ... */ 848 movl R(p0upa), %eax 849 movl $(UAREA_PAGES), %ecx 850 fillkptphys($PG_RW) 851 852/* Map proc0's KSTACK in the physical way ... */ 853 movl R(p0kpa), %eax 854 movl $(KSTACK_PAGES), %ecx 855 fillkptphys($PG_RW) 856 857/* Map ISA hole */ 858 movl $ISA_HOLE_START, %eax 859 movl $ISA_HOLE_LENGTH>>PAGE_SHIFT, %ecx 860 fillkptphys($PG_RW) 861 862/* Map space for the vm86 region */ 863 movl R(vm86phystk), %eax 864 movl $4, %ecx 865 fillkptphys($PG_RW) 866 867/* Map page 0 into the vm86 page table */ 868 movl $0, %eax 869 movl $0, %ebx 870 movl $1, %ecx 871 fillkpt(R(vm86pa), $PG_RW|PG_U) 872 873/* ...likewise for the ISA hole */ 874 movl $ISA_HOLE_START, %eax 875 movl $ISA_HOLE_START>>PAGE_SHIFT, %ebx 876 movl $ISA_HOLE_LENGTH>>PAGE_SHIFT, %ecx 877 fillkpt(R(vm86pa), $PG_RW|PG_U) 878 879#ifdef SMP 880/* Map cpu0's private page into global kmem (4K @ cpu0prvpage) */ 881 movl R(cpu0pp), %eax 882 movl $1, %ecx 883 fillkptphys($PG_RW) 884 885/* Map SMP page table page into global kmem FWIW */ 886 movl R(SMPptpa), %eax 887 movl $1, %ecx 888 fillkptphys($PG_RW) 889 890/* Map the private page into the SMP page table */ 891 movl R(cpu0pp), %eax 892 movl $0, %ebx /* pte offset = 0 */ 893 movl $1, %ecx /* one private page coming right up */ 894 fillkpt(R(SMPptpa), $PG_RW) 895 896/* ... and put the page table table in the pde. */ 897 movl R(SMPptpa), %eax 898 movl $MPPTDI, %ebx 899 movl $1, %ecx 900 fillkpt(R(IdlePTD), $PG_RW) 901 902/* Fakeup VA for the local apic to allow early traps. */ 903 ALLOCPAGES(1) 904 movl %esi, %eax 905 movl $(NPTEPG-1), %ebx /* pte offset = NTEPG-1 */ 906 movl $1, %ecx /* one private pt coming right up */ 907 fillkpt(R(SMPptpa), $PG_RW) 908#endif /* SMP */ 909 910/* install a pde for temporary double map of bottom of VA */ 911 movl R(KPTphys), %eax 912 xorl %ebx, %ebx 913 movl $NKPT, %ecx 914 fillkpt(R(IdlePTD), $PG_RW) 915 916/* 917 * For the non-PSE case, install PDEs for PTs covering the kernel. 918 * For the PSE case, do the same, but clobber the ones corresponding 919 * to the kernel (from btext to KERNend) with 4M ('PS') PDEs immediately 920 * after. 921 */ 922 movl R(KPTphys), %eax 923 movl $KPTDI, %ebx 924 movl $NKPT, %ecx 925 fillkpt(R(IdlePTD), $PG_RW) 926 cmpl $0,R(pseflag) 927 je done_pde 928 929 movl R(KERNend), %ecx 930 movl $KERNLOAD, %eax 931 subl %eax, %ecx 932 shrl $PDRSHIFT, %ecx 933 movl $(KPTDI+(KERNLOAD/(1 << PDRSHIFT))), %ebx 934 shll $PDESHIFT, %ebx 935 addl R(IdlePTD), %ebx 936 orl $(PG_V|PG_RW|PG_PS), %eax 9371: movl %eax, (%ebx) 938 addl $(1 << PDRSHIFT), %eax 939 addl $PDESIZE, %ebx 940 loop 1b 941 942done_pde: 943/* install a pde recursively mapping page directory as a page table */ 944 movl R(IdlePTD), %eax 945 movl $PTDPTDI, %ebx 946 movl $NPGPTD,%ecx 947 fillkpt(R(IdlePTD), $PG_RW) 948 949#ifdef PAE 950 movl R(IdlePTD), %eax 951 xorl %ebx, %ebx 952 movl $NPGPTD, %ecx 953 fillkpt(R(IdlePDPT), $0x0) 954#endif 955 956 ret 957