locore.s revision 13000
14Srgrimes/*- 24Srgrimes * Copyright (c) 1990 The Regents of the University of California. 34Srgrimes * All rights reserved. 44Srgrimes * 54Srgrimes * This code is derived from software contributed to Berkeley by 64Srgrimes * William Jolitz. 74Srgrimes * 84Srgrimes * Redistribution and use in source and binary forms, with or without 94Srgrimes * modification, are permitted provided that the following conditions 104Srgrimes * are met: 114Srgrimes * 1. Redistributions of source code must retain the above copyright 124Srgrimes * notice, this list of conditions and the following disclaimer. 134Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 144Srgrimes * notice, this list of conditions and the following disclaimer in the 154Srgrimes * documentation and/or other materials provided with the distribution. 164Srgrimes * 3. All advertising materials mentioning features or use of this software 174Srgrimes * must display the following acknowledgement: 184Srgrimes * This product includes software developed by the University of 194Srgrimes * California, Berkeley and its contributors. 204Srgrimes * 4. Neither the name of the University nor the names of its contributors 214Srgrimes * may be used to endorse or promote products derived from this software 224Srgrimes * without specific prior written permission. 234Srgrimes * 244Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 254Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 264Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 274Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 284Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 294Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 304Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 314Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 324Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 334Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 344Srgrimes * SUCH DAMAGE. 354Srgrimes * 36556Srgrimes * from: @(#)locore.s 7.3 (Berkeley) 5/13/91 3713000Sdg * $Id: locore.s,v 1.56 1995/09/16 21:31:55 pst Exp $ 384Srgrimes */ 394Srgrimes 404Srgrimes/* 41757Sdg * locore.s: FreeBSD machine support for the Intel 386 42757Sdg * originally from: locore.s, by William F. Jolitz 43757Sdg * 44757Sdg * Substantially rewritten by David Greenman, Rod Grimes, 45757Sdg * Bruce Evans, Wolfgang Solfrank, and many others. 464Srgrimes */ 474Srgrimes 482056Swollman#include "assym.s" /* system definitions */ 492056Swollman#include <machine/psl.h> /* processor status longword defs */ 502056Swollman#include <machine/pte.h> /* page table entry definitions */ 512056Swollman#include <sys/errno.h> /* error return codes */ 522056Swollman#include <machine/specialreg.h> /* x86 special registers */ 532056Swollman#include <machine/cputypes.h> /* x86 cpu type definitions */ 542056Swollman#include <sys/syscall.h> /* system call numbers */ 552056Swollman#include <machine/asmacros.h> /* miscellaneous asm macros */ 565908Sbde#include <sys/reboot.h> 573489Sphk#include "apm.h" 584Srgrimes 594Srgrimes/* 60757Sdg * XXX 61757Sdg * 624Srgrimes * Note: This version greatly munged to avoid various assembler errors 634Srgrimes * that may be fixed in newer versions of gas. Perhaps newer versions 644Srgrimes * will have more pleasant appearance. 654Srgrimes */ 664Srgrimes 67200Sdg/* 684Srgrimes * PTmap is recursive pagemap at top of virtual address space. 694Srgrimes * Within PTmap, the page directory can be found (third indirection). 704Srgrimes */ 713861Sbde .globl _PTmap,_PTD,_PTDpde 72592Srgrimes .set _PTmap,PTDPTDI << PDRSHIFT 73592Srgrimes .set _PTD,_PTmap + (PTDPTDI * NBPG) 74757Sdg .set _PTDpde,_PTD + (PTDPTDI * PDESIZE) 75592Srgrimes 763861Sbde/* 773861Sbde * Sysmap is the base address of the kernel page tables. 783861Sbde * It is a bogus interface for kgdb and isn't used by the kernel itself. 793861Sbde */ 80608Srgrimes .set _Sysmap,_PTmap + (KPTDI * NBPG) 814Srgrimes 824Srgrimes/* 834Srgrimes * APTmap, APTD is the alternate recursive pagemap. 844Srgrimes * It's used when modifying another process's page tables. 854Srgrimes */ 86592Srgrimes .globl _APTmap,_APTD,_APTDpde 87592Srgrimes .set _APTmap,APTDPTDI << PDRSHIFT 88592Srgrimes .set _APTD,_APTmap + (APTDPTDI * NBPG) 89757Sdg .set _APTDpde,_PTD + (APTDPTDI * PDESIZE) 904Srgrimes 914Srgrimes/* 924Srgrimes * Access to each processes kernel stack is via a region of 934Srgrimes * per-process address space (at the beginning), immediatly above 944Srgrimes * the user process stack. 954Srgrimes */ 96570Srgrimes .set _kstack,USRSTACK 97134Sdg .globl _kstack 984Srgrimes 99556Srgrimes/* 100556Srgrimes * Globals 101556Srgrimes */ 102556Srgrimes .data 103134Sdg 1043842Sdg .globl tmpstk 1053842Sdg .space 0x1000 /* space for tmpstk - temporary stack */ 1063842Sdgtmpstk: 1074012Sbde/* 1084012Sbde * Dummy frame at top of tmpstk to help debuggers print a nice stack trace. 1094012Sbde */ 1104012Sbde .long tmpstk+8 /* caller's %ebp */ 1114012Sbde .long _cpu_switch /* caller */ 1124012Sbde .long 0 /* %ebp == 0 should terminate trace */ 1134012Sbde .long _mvesp /* in case %ebp == 0 doesn't work ... */ 1144012Sbde .long 0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555 1153842Sdg 1163861Sbde .globl _boothowto,_bootdev 117134Sdg 1184600Sphk .globl _cpu,_cold,_atdevbase,_cpu_vendor,_cpu_id,_bootinfo 1196308Sphk .globl _cpu_high, _cpu_feature 1202783Ssos 121757Sdg_cpu: .long 0 /* are we 386, 386sx, or 486 */ 1222216Sbde_cpu_id: .long 0 /* stepping ID */ 1236308Sphk_cpu_high: .long 0 /* highest arg to CPUID */ 1246308Sphk_cpu_feature: .long 0 /* features */ 1252216Sbde_cpu_vendor: .space 20 /* CPU origin code */ 1265908Sbde_bootinfo: .space BOOTINFO_SIZE /* bootinfo that we can handle */ 127757Sdg_cold: .long 1 /* cold till we are not */ 128757Sdg_atdevbase: .long 0 /* location of start of iomem in virtual */ 129757Sdg_atdevphys: .long 0 /* location of device mapping ptes (phys) */ 1304Srgrimes 131757Sdg_KERNend: .long 0 /* phys addr end of kernel (just after bss) */ 132757Sdg 1333861Sbde .globl _IdlePTD 134757Sdg_IdlePTD: .long 0 /* phys addr of kernel PTD */ 1353861Sbde 136757Sdg_KPTphys: .long 0 /* phys addr of kernel page tables */ 1374Srgrimes 138757Sdg .globl _proc0paddr 139757Sdg_proc0paddr: .long 0 /* address of proc 0 address space */ 140134Sdg 141757Sdg#ifdef BDE_DEBUGGER 142757Sdg .globl _bdb_exists /* flag to indicate BDE debugger is available */ 1431321Sdg_bdb_exists: .long 0 144757Sdg#endif 145718Swollman 146556Srgrimes/* 147556Srgrimes * System Initialization 148556Srgrimes */ 1494Srgrimes .text 150134Sdg 151134Sdg/* 152200Sdg * btext: beginning of text section. 153200Sdg * Also the entry point (jumped to directly from the boot blocks). 154134Sdg */ 1551321SdgNON_GPROF_ENTRY(btext) 156757Sdg movw $0x1234,0x472 /* warm boot */ 1574Srgrimes 1583384Srgrimes /* Set up a real frame, some day we will be doing returns */ 1593384Srgrimes pushl %ebp 1603384Srgrimes movl %esp, %ebp 1613384Srgrimes 1622512Sbde /* Don't trust what the BIOS gives for eflags. */ 1635603Sbde pushl $PSL_KERNEL 1642486Sdg popfl 1652486Sdg 1664217Sphk /* Don't trust what the BIOS gives for %fs and %gs. */ 1674217Sphk mov %ds, %ax 1684217Sphk mov %ax, %fs 1694217Sphk mov %ax, %gs 1704217Sphk 1714Srgrimes /* 1723284Srgrimes * This code is called in different ways depending on what loaded 1733284Srgrimes * and started the kernel. This is used to detect how we get the 1743284Srgrimes * arguments from the other code and what we do with them. 1753284Srgrimes * 1763284Srgrimes * Old disk boot blocks: 1773284Srgrimes * (*btext)(howto, bootdev, cyloffset, esym); 1783284Srgrimes * [return address == 0, and can NOT be returned to] 1793284Srgrimes * [cyloffset was not supported by the FreeBSD boot code 1803284Srgrimes * and always passed in as 0] 1813284Srgrimes * [esym is also known as total in the boot code, and 1823284Srgrimes * was never properly supported by the FreeBSD boot code] 1833284Srgrimes * 1843284Srgrimes * Old diskless netboot code: 1853284Srgrimes * (*btext)(0,0,0,0,&nfsdiskless,0,0,0); 1863284Srgrimes * [return address != 0, and can NOT be returned to] 1873284Srgrimes * If we are being booted by this code it will NOT work, 1883284Srgrimes * so we are just going to halt if we find this case. 1893284Srgrimes * 1903284Srgrimes * New uniform boot code: 1913284Srgrimes * (*btext)(howto, bootdev, 0, 0, 0, &bootinfo) 1923284Srgrimes * [return address != 0, and can be returned to] 1933284Srgrimes * 1943284Srgrimes * There may seem to be a lot of wasted arguments in here, but 1953384Srgrimes * that is so the newer boot code can still load very old kernels 1963384Srgrimes * and old boot code can load new kernels. 1974Srgrimes */ 1983284Srgrimes 1993284Srgrimes /* 2003284Srgrimes * The old style disk boot blocks fake a frame on the stack and 2013284Srgrimes * did an lret to get here. The frame on the stack has a return 2023284Srgrimes * address of 0. 2033284Srgrimes */ 2043384Srgrimes cmpl $0,4(%ebp) 2053284Srgrimes je 2f /* olddiskboot: */ 2063284Srgrimes 2073284Srgrimes /* 2083284Srgrimes * We have some form of return address, so this is either the 2093284Srgrimes * old diskless netboot code, or the new uniform code. That can 2103284Srgrimes * be detected by looking at the 5th argument, it if is 0 we 2113284Srgrimes * we are being booted by the new unifrom boot code. 2123284Srgrimes */ 2133384Srgrimes cmpl $0,24(%ebp) 2143284Srgrimes je 1f /* newboot: */ 2153284Srgrimes 2163284Srgrimes /* 2173284Srgrimes * Seems we have been loaded by the old diskless boot code, we 2183284Srgrimes * don't stand a chance of running as the diskless structure 2193284Srgrimes * changed considerably between the two, so just halt. 2203284Srgrimes */ 2213284Srgrimes hlt 2223284Srgrimes 2233284Srgrimes /* 2243384Srgrimes * We have been loaded by the new uniform boot code. 2253384Srgrimes * Lets check the bootinfo version, and if we do not understand 2263384Srgrimes * it we return to the loader with a status of 1 to indicate this error 2273284Srgrimes */ 2283284Srgrimes1: /* newboot: */ 2293384Srgrimes movl 28(%ebp),%ebx /* &bootinfo.version */ 2305908Sbde movl BI_VERSION(%ebx),%eax 2313384Srgrimes cmpl $1,%eax /* We only understand version 1 */ 2323384Srgrimes je 1f 2333384Srgrimes movl $1,%eax /* Return status */ 2343384Srgrimes leave 2353384Srgrimes ret 2363284Srgrimes 2373384Srgrimes1: 2383284Srgrimes /* 2393384Srgrimes * If we have a kernelname copy it in 2403384Srgrimes */ 2415908Sbde movl BI_KERNELNAME(%ebx),%esi 2423384Srgrimes cmpl $0,%esi 2439344Sdg je 2f /* No kernelname */ 2449344Sdg movl $MAXPATHLEN,%ecx /* Brute force!!! */ 2453384Srgrimes lea _kernelname-KERNBASE,%edi 2469344Sdg cmpb $'/',(%esi) /* Make sure it starts with a slash */ 2479344Sdg je 1f 2489344Sdg movb $'/',(%edi) 2499344Sdg incl %edi 2509344Sdg decl %ecx 2519344Sdg1: 2523384Srgrimes cld 2533384Srgrimes rep 2543384Srgrimes movsb 2553384Srgrimes 2569344Sdg2: 2574600Sphk /* 2585908Sbde * Determine the size of the boot loader's copy of the bootinfo 2595908Sbde * struct. This is impossible to do properly because old versions 2605908Sbde * of the struct don't contain a size field and there are 2 old 2615908Sbde * versions with the same version number. 2624600Sphk */ 2635908Sbde movl $BI_ENDCOMMON,%ecx /* prepare for sizeless version */ 2645908Sbde testl $RB_BOOTINFO,8(%ebp) /* bi_size (and bootinfo) valid? */ 2655908Sbde je got_bi_size /* no, sizeless version */ 2665908Sbde movl BI_SIZE(%ebx),%ecx 2675908Sbdegot_bi_size: 2685908Sbde 2695908Sbde /* 2705908Sbde * Copy the common part of the bootinfo struct 2715908Sbde */ 2724600Sphk movl %ebx,%esi 2735908Sbde movl $_bootinfo-KERNBASE,%edi 2745908Sbde cmpl $BOOTINFO_SIZE,%ecx 2755908Sbde jbe got_common_bi_size 2764600Sphk movl $BOOTINFO_SIZE,%ecx 2775908Sbdegot_common_bi_size: 2784600Sphk cld 2794600Sphk rep 2804600Sphk movsb 2814600Sphk 2823426Srgrimes#ifdef NFS 2833384Srgrimes /* 2843384Srgrimes * If we have a nfs_diskless structure copy it in 2853384Srgrimes */ 2865908Sbde movl BI_NFS_DISKLESS(%ebx),%esi 2873384Srgrimes cmpl $0,%esi 2883384Srgrimes je 2f 2893384Srgrimes lea _nfs_diskless-KERNBASE,%edi 2903384Srgrimes movl $NFSDISKLESS_SIZE,%ecx 2913384Srgrimes cld 2923384Srgrimes rep 2933384Srgrimes movsb 2943795Sphk lea _nfs_diskless_valid-KERNBASE,%edi 2953795Sphk movl $1,(%edi) 2963406Sdg#endif 2973384Srgrimes 2983384Srgrimes /* 2993284Srgrimes * The old style disk boot. 3003284Srgrimes * (*btext)(howto, bootdev, cyloffset, esym); 3013384Srgrimes * Note that the newer boot code just falls into here to pick 3023384Srgrimes * up howto and bootdev, cyloffset and esym are no longer used 3033284Srgrimes */ 3043284Srgrimes2: /* olddiskboot: */ 3053384Srgrimes movl 8(%ebp),%eax 306570Srgrimes movl %eax,_boothowto-KERNBASE 3073384Srgrimes movl 12(%ebp),%eax 308570Srgrimes movl %eax,_bootdev-KERNBASE 3092783Ssos 3103489Sphk#if NAPM > 0 3116512Sphk /* call APM BIOS driver setup (i386/apm/apm_setup.s) */ 3126512Sphk call _apm_setup 3133489Sphk#endif /* NAPM */ 3143258Sdg 3151998Swollman /* Find out our CPU type. */ 3161321Sdg 3171998Swollman /* Try to toggle alignment check flag; does not exist on 386. */ 3181998Swollman pushfl 3191998Swollman popl %eax 3201998Swollman movl %eax,%ecx 3211998Swollman orl $PSL_AC,%eax 3221998Swollman pushl %eax 3231998Swollman popfl 3241998Swollman pushfl 3251998Swollman popl %eax 3261998Swollman xorl %ecx,%eax 3271998Swollman andl $PSL_AC,%eax 3281998Swollman pushl %ecx 3291998Swollman popfl 3301998Swollman 3311998Swollman testl %eax,%eax 3321998Swollman jnz 1f 3331998Swollman movl $CPU_386,_cpu-KERNBASE 334556Srgrimes jmp 2f 3351998Swollman 3361998Swollman1: /* Try to toggle identification flag; does not exist on early 486s. */ 3371998Swollman pushfl 3381998Swollman popl %eax 3391998Swollman movl %eax,%ecx 3401998Swollman xorl $PSL_ID,%eax 3411998Swollman pushl %eax 3421998Swollman popfl 3431998Swollman pushfl 3441998Swollman popl %eax 3451998Swollman xorl %ecx,%eax 3461998Swollman andl $PSL_ID,%eax 3471998Swollman pushl %ecx 3481998Swollman popfl 3491998Swollman 3501998Swollman testl %eax,%eax 3511998Swollman jnz 1f 3521998Swollman movl $CPU_486,_cpu-KERNBASE 3532495Spst 3542495Spst /* check for Cyrix 486DLC -- based on check routine */ 3552495Spst /* documented in "Cx486SLC/e SMM Programmer's Guide" */ 3562495Spst xorw %dx,%dx 3572495Spst cmpw %dx,%dx # set flags to known state 3582495Spst pushfw 3592495Spst popw %cx # store flags in ecx 3602495Spst movw $0xffff,%ax 3612495Spst movw $0x0004,%bx 3622495Spst divw %bx 3632495Spst pushfw 3642495Spst popw %ax 3652495Spst andw $0x08d5,%ax # mask off important bits 3662495Spst andw $0x08d5,%cx 3672495Spst cmpw %ax,%cx 3682495Spst 3692495Spst jnz 2f # if flags changed, Intel chip 3702495Spst 3712495Spst movl $CPU_486DLC,_cpu-KERNBASE # set CPU value for Cyrix 3722495Spst movl $0x69727943,_cpu_vendor-KERNBASE # store vendor string 3732495Spst movw $0x0078,_cpu_vendor-KERNBASE+4 3742495Spst 37510826Spst#ifndef CYRIX_CACHE_WORKS 3762495Spst /* Disable caching of the ISA hole only. */ 37710826Spst invd 3782495Spst movb $CCR0,%al # Configuration Register index (CCR0) 3792495Spst outb %al,$0x22 38010826Spst inb $0x23,%al 3813117Spst orb $(CCR0_NC1|CCR0_BARB),%al 38210826Spst movb %al,%ah 38310826Spst movb $CCR0,%al 38410826Spst outb %al,$0x22 38510826Spst movb %ah,%al 3862495Spst outb %al,$0x23 3872495Spst invd 38810826Spst#else /* CYRIX_CACHE_WORKS */ 38910826Spst /* Set cache parameters */ 39010826Spst invd # Start with guaranteed clean cache 39110826Spst movb $CCR0,%al # Configuration Register index (CCR0) 39210826Spst outb %al,$0x22 39310826Spst inb $0x23,%al 39410826Spst andb $~CCR0_NC0,%al 39510826Spst#ifndef CYRIX_CACHE_REALLY_WORKS 39610826Spst orb $(CCR0_NC1|CCR0_BARB),%al 39710826Spst#else 39810826Spst orb $CCR0_NC1,%al 39910826Spst#endif 40010826Spst movb %al,%ah 40110826Spst movb $CCR0,%al 40210826Spst outb %al,$0x22 40310826Spst movb %ah,%al 40410826Spst outb %al,$0x23 40510826Spst /* clear non-cacheable region 1 */ 40610826Spst movb $(NCR1+2),%al 40710826Spst outb %al,$0x22 40810826Spst movb $NCR_SIZE_0K,%al 40910826Spst outb %al,$0x23 41010826Spst /* clear non-cacheable region 2 */ 41110826Spst movb $(NCR2+2),%al 41210826Spst outb %al,$0x22 41310826Spst movb $NCR_SIZE_0K,%al 41410826Spst outb %al,$0x23 41510826Spst /* clear non-cacheable region 3 */ 41610826Spst movb $(NCR3+2),%al 41710826Spst outb %al,$0x22 41810826Spst movb $NCR_SIZE_0K,%al 41910826Spst outb %al,$0x23 42010826Spst /* clear non-cacheable region 4 */ 42110826Spst movb $(NCR4+2),%al 42210826Spst outb %al,$0x22 42310826Spst movb $NCR_SIZE_0K,%al 42410826Spst outb %al,$0x23 42510826Spst /* enable caching in CR0 */ 42610826Spst movl %cr0,%eax 42710826Spst andl $~(CR0_CD|CR0_NW),%eax 42810826Spst movl %eax,%cr0 42910826Spst invd 43010826Spst#endif /* CYRIX_CACHE_WORKS */ 4311998Swollman jmp 2f 4321998Swollman 4331998Swollman1: /* Use the `cpuid' instruction. */ 4341998Swollman xorl %eax,%eax 4356308Sphk .byte 0x0f,0xa2 # cpuid 0 4366308Sphk movl %eax,_cpu_high-KERNBASE # highest capability 4371998Swollman movl %ebx,_cpu_vendor-KERNBASE # store vendor string 4381998Swollman movl %edx,_cpu_vendor+4-KERNBASE 4391998Swollman movl %ecx,_cpu_vendor+8-KERNBASE 4401998Swollman movb $0,_cpu_vendor+12-KERNBASE 4411998Swollman 4421998Swollman movl $1,%eax 4436308Sphk .byte 0x0f,0xa2 # cpuid 1 4441998Swollman movl %eax,_cpu_id-KERNBASE # store cpu_id 4456308Sphk movl %edx,_cpu_feature-KERNBASE # store cpu_feature 4466308Sphk rorl $8,%eax # extract family type 4471998Swollman andl $15,%eax 4481998Swollman cmpl $5,%eax 4491998Swollman jae 1f 4501998Swollman 4511998Swollman /* less than Pentium; must be 486 */ 4521998Swollman movl $CPU_486,_cpu-KERNBASE 45313000Sdg jmp 3f 45413000Sdg1: 45513000Sdg /* a Pentium? */ 45613000Sdg cmpl $5,%eax 45713000Sdg jne 2f 45813000Sdg movl $CPU_586,_cpu-KERNBASE 45913000Sdg jmp 3f 460556Srgrimes2: 46113000Sdg /* Greater than Pentium...call it a Pentium Pro */ 46213000Sdg movl $CPU_686,_cpu-KERNBASE 46313000Sdg3: 464556Srgrimes 4654Srgrimes /* 4664Srgrimes * Finished with old stack; load new %esp now instead of later so 4674Srgrimes * we can trace this code without having to worry about the trace 4684Srgrimes * trap clobbering the memory test or the zeroing of the bss+bootstrap 4694Srgrimes * page tables. 4704Srgrimes * 4714Srgrimes * XXX - wdboot clears the bss after testing that this is safe. 4724Srgrimes * This is too wasteful - memory below 640K is scarce. The boot 4734Srgrimes * program should check: 4744Srgrimes * text+data <= &stack_variable - more_space_for_stack 4754Srgrimes * text+data+bss+pad+space_for_page_tables <= end_of_memory 4764Srgrimes * Oops, the gdt is in the carcass of the boot program so clearing 4774Srgrimes * the rest of memory is still not possible. 4784Srgrimes */ 479757Sdg movl $tmpstk-KERNBASE,%esp /* bootstrap stack end location */ 4804Srgrimes 481570Srgrimes/* 482570Srgrimes * Virtual address space of kernel: 483570Srgrimes * 484570Srgrimes * text | data | bss | [syms] | page dir | proc0 kernel stack | usr stk map | Sysmap 485974Sdg * pages: 1 UPAGES (2) 1 NKPT (7) 486570Srgrimes */ 487570Srgrimes 4884Srgrimes/* find end of kernel image */ 489570Srgrimes movl $_end-KERNBASE,%ecx 490757Sdg addl $NBPG-1,%ecx /* page align up */ 4914Srgrimes andl $~(NBPG-1),%ecx 4921321Sdg movl %ecx,%esi /* esi = start of free memory */ 493757Sdg movl %ecx,_KERNend-KERNBASE /* save end of kernel */ 4944Srgrimes 495757Sdg/* clear bss */ 496570Srgrimes movl $_edata-KERNBASE,%edi 497760Srgrimes subl %edi,%ecx /* get amount to clear */ 498757Sdg xorl %eax,%eax /* specify zero fill */ 4994Srgrimes cld 5004Srgrimes rep 5014Srgrimes stosb 5024Srgrimes 5035908Sbde#ifdef DDB 5045908Sbde/* include symbols in "kernel image" if they are loaded */ 5055908Sbde movl _bootinfo+BI_ESYMTAB-KERNBASE,%edi 5065908Sbde testl %edi,%edi 5075908Sbde je over_symalloc 5085908Sbde addl $NBPG-1,%edi 5095908Sbde andl $~(NBPG-1),%edi 5105908Sbde movl %edi,%esi 5115908Sbde movl %esi,_KERNend-KERNBASE 5125908Sbde movl $KERNBASE,%edi 5135908Sbde addl %edi,_bootinfo+BI_SYMTAB-KERNBASE 5145908Sbde addl %edi,_bootinfo+BI_ESYMTAB-KERNBASE 5155908Sbdeover_symalloc: 5165908Sbde#endif 5175908Sbde 518608Srgrimes/* 519974Sdg * The value in esi is both the end of the kernel bss and a pointer to 520974Sdg * the kernel page directory, and is used by the rest of locore to build 521974Sdg * the tables. 522974Sdg * esi + 1(page dir) + 2(UPAGES) + 1(p0stack) + NKPT(number of kernel 523757Sdg * page table pages) is then passed on the stack to init386(first) as 524757Sdg * the value first. esi should ALWAYS be page aligned!! 525608Srgrimes */ 526757Sdg movl %esi,%ecx /* Get current first availiable address */ 527608Srgrimes 528757Sdg/* clear pagetables, page directory, stack, etc... */ 529757Sdg movl %esi,%edi /* base (page directory) */ 530974Sdg movl $((1+UPAGES+1+NKPT)*NBPG),%ecx /* amount to clear */ 531757Sdg xorl %eax,%eax /* specify zero fill */ 532757Sdg cld 533757Sdg rep 534757Sdg stosb 535757Sdg 536757Sdg/* physical address of Idle proc/kernel page directory */ 537570Srgrimes movl %esi,_IdlePTD-KERNBASE 5384Srgrimes 539592Srgrimes/* 540592Srgrimes * fillkpt 541592Srgrimes * eax = (page frame address | control | status) == pte 542592Srgrimes * ebx = address of page table 543592Srgrimes * ecx = how many pages to map 544592Srgrimes */ 5454Srgrimes#define fillkpt \ 5464Srgrimes1: movl %eax,(%ebx) ; \ 547570Srgrimes addl $NBPG,%eax ; /* increment physical address */ \ 5484Srgrimes addl $4,%ebx ; /* next pte */ \ 5494Srgrimes loop 1b ; 5504Srgrimes 5514Srgrimes/* 5524Srgrimes * Map Kernel 5534Srgrimes * 5544Srgrimes * First step - build page tables 5554Srgrimes */ 556757Sdg#if defined (KGDB) || defined (BDE_DEBUGGER) 557757Sdg movl _KERNend-KERNBASE,%ecx /* this much memory, */ 558757Sdg shrl $PGSHIFT,%ecx /* for this many PTEs */ 559757Sdg#ifdef BDE_DEBUGGER 560757Sdg cmpl $0xa0,%ecx /* XXX - cover debugger pages */ 561200Sdg jae 1f 562200Sdg movl $0xa0,%ecx 563200Sdg1: 564757Sdg#endif /* BDE_DEBUGGER */ 5652512Sbde movl $PG_V|PG_KW,%eax /* kernel R/W, valid */ 566757Sdg lea ((1+UPAGES+1)*NBPG)(%esi),%ebx /* phys addr of kernel PT base */ 567757Sdg movl %ebx,_KPTphys-KERNBASE /* save in global */ 5684Srgrimes fillkpt 5694Srgrimes 570757Sdg#else /* !KGDB && !BDE_DEBUGGER */ 571757Sdg /* write protect kernel text (doesn't do a thing for 386's - only 486's) */ 572757Sdg movl $_etext-KERNBASE,%ecx /* get size of text */ 5733842Sdg addl $NBPG-1,%ecx /* round up to page */ 574757Sdg shrl $PGSHIFT,%ecx /* for this many PTEs */ 575757Sdg movl $PG_V|PG_KR,%eax /* specify read only */ 5763842Sdg#if 0 5773842Sdg movl $_etext,%ecx /* get size of text */ 5783842Sdg subl $_btext,%ecx 5793842Sdg addl $NBPG-1,%ecx /* round up to page */ 5803842Sdg shrl $PGSHIFT,%ecx /* for this many PTEs */ 5813842Sdg movl $_btext-KERNBASE,%eax /* get offset to physical memory */ 5823842Sdg orl $PG_V|PG_KR,%eax /* specify read only */ 5833842Sdg#endif 584757Sdg lea ((1+UPAGES+1)*NBPG)(%esi),%ebx /* phys addr of kernel PT base */ 585757Sdg movl %ebx,_KPTphys-KERNBASE /* save in global */ 586757Sdg fillkpt 587757Sdg 588757Sdg /* data and bss are r/w */ 589757Sdg andl $PG_FRAME,%eax /* strip to just addr of bss */ 590757Sdg movl _KERNend-KERNBASE,%ecx /* calculate size */ 591757Sdg subl %eax,%ecx 592757Sdg shrl $PGSHIFT,%ecx 593757Sdg orl $PG_V|PG_KW,%eax /* valid, kernel read/write */ 594757Sdg fillkpt 5951321Sdg#endif /* KGDB || BDE_DEBUGGER */ 596757Sdg 59710762Sdg/* now initialize the page dir, upages, and p0stack PT */ 598757Sdg 59910762Sdg movl $(1+UPAGES+1),%ecx /* number of PTEs */ 600757Sdg movl %esi,%eax /* phys address of PTD */ 601757Sdg andl $PG_FRAME,%eax /* convert to PFN, should be a NOP */ 6022512Sbde orl $PG_V|PG_KW,%eax /* valid, kernel read/write */ 603757Sdg movl %esi,%ebx /* calculate pte offset to ptd */ 604757Sdg shrl $PGSHIFT-2,%ebx 605757Sdg addl %esi,%ebx /* address of page directory */ 606757Sdg addl $((1+UPAGES+1)*NBPG),%ebx /* offset to kernel page tables */ 607757Sdg fillkpt 6081321Sdg 6094Srgrimes/* map I/O memory map */ 6104Srgrimes 611757Sdg movl _KPTphys-KERNBASE,%ebx /* base of kernel page tables */ 612757Sdg lea (0xa0 * PTESIZE)(%ebx),%ebx /* hardwire ISA hole at KERNBASE + 0xa0000 */ 613757Sdg movl $0x100-0xa0,%ecx /* for this many pte s, */ 6141046Sdg movl $(0xa0000|PG_V|PG_KW|PG_N),%eax /* valid, kernel read/write, non-cacheable */ 615757Sdg movl %ebx,_atdevphys-KERNBASE /* save phys addr of ptes */ 6164Srgrimes fillkpt 6174Srgrimes 6184Srgrimes /* map proc 0's kernel stack into user page table page */ 6194Srgrimes 620757Sdg movl $UPAGES,%ecx /* for this many pte s, */ 621757Sdg lea (1*NBPG)(%esi),%eax /* physical address in proc 0 */ 622757Sdg lea (KERNBASE)(%eax),%edx /* change into virtual addr */ 623757Sdg movl %edx,_proc0paddr-KERNBASE /* save VA for proc 0 init */ 624757Sdg orl $PG_V|PG_KW,%eax /* valid, kernel read/write */ 625757Sdg lea ((1+UPAGES)*NBPG)(%esi),%ebx /* addr of stack page table in proc 0 */ 626757Sdg addl $(KSTKPTEOFF * PTESIZE),%ebx /* offset to kernel stack PTE */ 6274Srgrimes fillkpt 6284Srgrimes 6294Srgrimes/* 630757Sdg * Initialize kernel page table directory 6314Srgrimes */ 6324Srgrimes /* install a pde for temporary double map of bottom of VA */ 633757Sdg movl _KPTphys-KERNBASE,%eax 634757Sdg orl $PG_V|PG_KW,%eax /* valid, kernel read/write */ 635757Sdg movl %eax,(%esi) /* which is where temp maps! */ 6364Srgrimes 637757Sdg /* initialize kernel pde's */ 638974Sdg movl $(NKPT),%ecx /* for this many PDEs */ 639757Sdg lea (KPTDI*PDESIZE)(%esi),%ebx /* offset of pde for kernel */ 6404Srgrimes fillkpt 6414Srgrimes 6424Srgrimes /* install a pde recursively mapping page directory as a page table! */ 643757Sdg movl %esi,%eax /* phys address of ptd in proc 0 */ 644757Sdg orl $PG_V|PG_KW,%eax /* pde entry is valid */ 645757Sdg movl %eax,PTDPTDI*PDESIZE(%esi) /* which is where PTmap maps! */ 6464Srgrimes 6474Srgrimes /* install a pde to map kernel stack for proc 0 */ 648757Sdg lea ((1+UPAGES)*NBPG)(%esi),%eax /* physical address of pt in proc 0 */ 649757Sdg orl $PG_V|PG_KW,%eax /* pde entry is valid */ 650757Sdg movl %eax,KSTKPTDI*PDESIZE(%esi) /* which is where kernel stack maps! */ 6514Srgrimes 652757Sdg#ifdef BDE_DEBUGGER 6534Srgrimes /* copy and convert stuff from old gdt and idt for debugger */ 6544Srgrimes 655757Sdg cmpl $0x0375c339,0x96104 /* XXX - debugger signature */ 6564Srgrimes jne 1f 657570Srgrimes movb $1,_bdb_exists-KERNBASE 6584Srgrimes1: 6594Srgrimes pushal 6604Srgrimes subl $2*6,%esp 6614Srgrimes 6624Srgrimes sgdt (%esp) 663757Sdg movl 2(%esp),%esi /* base address of current gdt */ 664570Srgrimes movl $_gdt-KERNBASE,%edi 6654Srgrimes movl %edi,2(%esp) 6664Srgrimes movl $8*18/4,%ecx 6671688Sdg cld 668757Sdg rep /* copy gdt */ 6694Srgrimes movsl 670570Srgrimes movl $_gdt-KERNBASE,-8+2(%edi) /* adjust gdt self-ptr */ 6714Srgrimes movb $0x92,-8+5(%edi) 6724Srgrimes 6734Srgrimes sidt 6(%esp) 674757Sdg movl 6+2(%esp),%esi /* base address of current idt */ 675757Sdg movl 8+4(%esi),%eax /* convert dbg descriptor to ... */ 6764Srgrimes movw 8(%esi),%ax 677570Srgrimes movl %eax,bdb_dbg_ljmp+1-KERNBASE /* ... immediate offset ... */ 6784Srgrimes movl 8+2(%esi),%eax 679570Srgrimes movw %ax,bdb_dbg_ljmp+5-KERNBASE /* ... and selector for ljmp */ 680757Sdg movl 24+4(%esi),%eax /* same for bpt descriptor */ 6814Srgrimes movw 24(%esi),%ax 682570Srgrimes movl %eax,bdb_bpt_ljmp+1-KERNBASE 6834Srgrimes movl 24+2(%esi),%eax 684570Srgrimes movw %ax,bdb_bpt_ljmp+5-KERNBASE 6854Srgrimes 686570Srgrimes movl $_idt-KERNBASE,%edi 6874Srgrimes movl %edi,6+2(%esp) 6884Srgrimes movl $8*4/4,%ecx 6891688Sdg cld 690757Sdg rep /* copy idt */ 6914Srgrimes movsl 6924Srgrimes 6934Srgrimes lgdt (%esp) 6944Srgrimes lidt 6(%esp) 6954Srgrimes 6964Srgrimes addl $2*6,%esp 6974Srgrimes popal 6981321Sdg#endif /* BDE_DEBUGGER */ 6994Srgrimes 700592Srgrimes /* load base of page directory and enable mapping */ 701757Sdg movl %esi,%eax /* phys address of ptd in proc 0 */ 702757Sdg movl %eax,%cr3 /* load ptd addr into mmu */ 703757Sdg movl %cr0,%eax /* get control word */ 704757Sdg orl $CR0_PE|CR0_PG,%eax /* enable paging */ 705757Sdg movl %eax,%cr0 /* and let's page NOW! */ 7064Srgrimes 707757Sdg pushl $begin /* jump to high mem */ 7084Srgrimes ret 7094Srgrimes 710570Srgrimesbegin: /* now running relocated at KERNBASE where the system is linked to run */ 711757Sdg movl _atdevphys,%edx /* get pte PA */ 712757Sdg subl _KPTphys,%edx /* remove base of ptes, now have phys offset */ 713757Sdg shll $PGSHIFT-2,%edx /* corresponding to virt offset */ 714757Sdg addl $KERNBASE,%edx /* add virtual base */ 715570Srgrimes movl %edx,_atdevbase 7163728Sphk 71710762Sdg /* set up bootstrap stack */ 71810762Sdg movl $_kstack+UPAGES*NBPG,%esp /* bootstrap stack end location */ 719757Sdg xorl %eax,%eax /* mark end of frames */ 7204Srgrimes movl %eax,%ebp 721570Srgrimes movl _proc0paddr,%eax 722570Srgrimes movl %esi,PCB_CR3(%eax) 7234Srgrimes 724757Sdg#ifdef BDE_DEBUGGER 7254Srgrimes /* relocate debugger gdt entries */ 7264Srgrimes 727757Sdg movl $_gdt+8*9,%eax /* adjust slots 9-17 */ 7284Srgrimes movl $9,%ecx 7294Srgrimesreloc_gdt: 7301321Sdg movb $KERNBASE>>24,7(%eax) /* top byte of base addresses, was 0, */ 731757Sdg addl $8,%eax /* now KERNBASE>>24 */ 7324Srgrimes loop reloc_gdt 7334Srgrimes 7344Srgrimes cmpl $0,_bdb_exists 7354Srgrimes je 1f 7364Srgrimes int $3 7374Srgrimes1: 7381321Sdg#endif /* BDE_DEBUGGER */ 7394Srgrimes 740608Srgrimes /* 74110762Sdg * Prepare "first" - physical address of first available page 74210762Sdg * after the kernel+pdir+upages+p0stack+page tables 743608Srgrimes */ 744974Sdg lea ((1+UPAGES+1+NKPT)*NBPG)(%esi),%esi 745608Srgrimes 746757Sdg pushl %esi /* value of first for init386(first) */ 747757Sdg call _init386 /* wire 386 chip for unix operation */ 7481549Srgrimes popl %esi 749200Sdg 7501549Srgrimes .globl __ucodesel,__udatasel 7511549Srgrimes 7521549Srgrimes pushl $0 /* unused */ 7531549Srgrimes pushl __udatasel /* ss */ 7541549Srgrimes pushl $0 /* esp - filled in by execve() */ 7555603Sbde pushl $PSL_USER /* eflags (IOPL 0, int enab) */ 7561549Srgrimes pushl __ucodesel /* cs */ 7571549Srgrimes pushl $0 /* eip - filled in by execve() */ 7581549Srgrimes subl $(12*4),%esp /* space for rest of registers */ 7591549Srgrimes 7601549Srgrimes pushl %esp /* call main with frame pointer */ 761757Sdg call _main /* autoconfiguration, mountroot etc */ 7624Srgrimes 7631549Srgrimes addl $(13*4),%esp /* back to a frame we can return with */ 7641549Srgrimes 765134Sdg /* 766570Srgrimes * now we've run main() and determined what cpu-type we are, we can 7675603Sbde * enable write protection and alignment checking on i486 cpus and 7685603Sbde * above. 7691058Sdg */ 77013000Sdg#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU) 7711058Sdg cmpl $CPUCLASS_386,_cpu_class 7721058Sdg je 1f 7731058Sdg movl %cr0,%eax /* get control word */ 7745603Sbde orl $CR0_WP|CR0_AM,%eax /* enable i486 features */ 7751058Sdg movl %eax,%cr0 /* and do it */ 7761058Sdg#endif 7771058Sdg /* 778134Sdg * on return from main(), we are process 1 779134Sdg * set up address space and stack so that we can 'return' to user mode 780134Sdg */ 7811058Sdg1: 7824Srgrimes movl __ucodesel,%eax 7834Srgrimes movl __udatasel,%ecx 7841549Srgrimes 7854Srgrimes movl %cx,%ds 7864Srgrimes movl %cx,%es 787757Sdg movl %ax,%fs /* double map cs to fs */ 788757Sdg movl %cx,%gs /* and ds to gs */ 7891549Srgrimes iret /* goto user! */ 7904Srgrimes 7911549Srgrimes#define LCALL(x,y) .byte 0x9a ; .long y ; .word x 7924Srgrimes 793200SdgNON_GPROF_ENTRY(sigcode) 794592Srgrimes call SIGF_HANDLER(%esp) 795757Sdg lea SIGF_SC(%esp),%eax /* scp (the call may have clobbered the */ 796757Sdg /* copy at 8(%esp)) */ 7974Srgrimes pushl %eax 798757Sdg pushl %eax /* junk to fake return address */ 799757Sdg movl $103,%eax /* XXX sigreturn() */ 800757Sdg LCALL(0x7,0) /* enter kernel with args on stack */ 801757Sdg hlt /* never gets here */ 8024Srgrimes 8034Srgrimes .globl _szsigcode 8044Srgrimes_szsigcode: 8054Srgrimes .long _szsigcode-_sigcode 806