locore.s revision 13014
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 371998Swollman * $Id: locore.s,v 1.57 1995/12/24 08:10:39 davidg 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 48757Sdg#include "assym.s" /* system definitions */ 49757Sdg#include <machine/psl.h> /* processor status longword defs */ 50757Sdg#include <machine/pte.h> /* page table entry definitions */ 51757Sdg#include <sys/errno.h> /* error return codes */ 52757Sdg#include <machine/specialreg.h> /* x86 special registers */ 53757Sdg#include <machine/cputypes.h> /* x86 cpu type definitions */ 54757Sdg#include <sys/syscall.h> /* system call numbers */ 55757Sdg#include <machine/asmacros.h> /* miscellaneous asm macros */ 56757Sdg#include <sys/reboot.h> 574Srgrimes#include "apm.h" 584Srgrimes 59757Sdg/* 60757Sdg * XXX 614Srgrimes * 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 */ 66200Sdg 674Srgrimes/* 684Srgrimes * PTmap is recursive pagemap at top of virtual address space. 694Srgrimes * Within PTmap, the page directory can be found (third indirection). 70592Srgrimes */ 71592Srgrimes .globl _PTmap,_PTD,_PTDpde 72592Srgrimes .set _PTmap,PTDPTDI << PDRSHIFT 73757Sdg .set _PTD,_PTmap + (PTDPTDI * NBPG) 74592Srgrimes .set _PTDpde,_PTD + (PTDPTDI * PDESIZE) 75757Sdg 76608Srgrimes/* 774Srgrimes * Sysmap is the base address of the kernel page tables. 784Srgrimes * It is a bogus interface for kgdb and isn't used by the kernel itself. 794Srgrimes */ 804Srgrimes .set _Sysmap,_PTmap + (KPTDI * NBPG) 814Srgrimes 82592Srgrimes/* 83592Srgrimes * APTmap, APTD is the alternate recursive pagemap. 84592Srgrimes * It's used when modifying another process's page tables. 85757Sdg */ 864Srgrimes .globl _APTmap,_APTD,_APTDpde 874Srgrimes .set _APTmap,APTDPTDI << PDRSHIFT 884Srgrimes .set _APTD,_APTmap + (APTDPTDI * NBPG) 894Srgrimes .set _APTDpde,_PTD + (APTDPTDI * PDESIZE) 904Srgrimes 914Srgrimes/* 92570Srgrimes * Access to each processes kernel stack is via a region of 93134Sdg * per-process address space (at the beginning), immediatly above 944Srgrimes * the user process stack. 95556Srgrimes */ 96556Srgrimes .set _kstack,USRSTACK 97556Srgrimes .globl _kstack 98556Srgrimes 99556Srgrimes/* 100757Sdg * Globals 101134Sdg */ 102592Srgrimes .data 103134Sdg 1041998Swollman .globl tmpstk 105757Sdg .space 0x1000 /* space for tmpstk - temporary stack */ 1061998Swollmantmpstk: 1071998Swollman/* 108757Sdg * Dummy frame at top of tmpstk to help debuggers print a nice stack trace. 109757Sdg */ 110757Sdg .long tmpstk+8 /* caller's %ebp */ 1114Srgrimes .long _cpu_switch /* caller */ 112757Sdg .long 0 /* %ebp == 0 should terminate trace */ 113757Sdg .long _mvesp /* in case %ebp == 0 doesn't work ... */ 114757Sdg .long 0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555 115592Srgrimes 116757Sdg .globl _boothowto,_bootdev 117757Sdg 1184Srgrimes .globl _cpu,_cold,_atdevbase,_cpu_vendor,_cpu_id,_bootinfo 119757Sdg .globl _cpu_high, _cpu_feature 120757Sdg 121718Swollman_cpu: .long 0 /* are we 386, 386sx, or 486 */ 122757Sdg_cpu_id: .long 0 /* stepping ID */ 123757Sdg_cpu_high: .long 0 /* highest arg to CPUID */ 124134Sdg_cpu_feature: .long 0 /* features */ 125757Sdg_cpu_vendor: .space 20 /* CPU origin code */ 126757Sdg_bootinfo: .space BOOTINFO_SIZE /* bootinfo that we can handle */ 1271321Sdg_cold: .long 1 /* cold till we are not */ 128757Sdg_atdevbase: .long 0 /* location of start of iomem in virtual */ 129718Swollman_atdevphys: .long 0 /* location of device mapping ptes (phys) */ 130757Sdg 131974Sdg_KERNend: .long 0 /* phys addr end of kernel (just after bss) */ 1324Srgrimes 133134Sdg .globl _IdlePTD 134134Sdg_IdlePTD: .long 0 /* phys addr of kernel PTD */ 135556Srgrimes 136556Srgrimes_KPTphys: .long 0 /* phys addr of kernel page tables */ 137556Srgrimes 1384Srgrimes .globl _proc0paddr 139134Sdg_proc0paddr: .long 0 /* address of proc 0 address space */ 140134Sdg 141200Sdg#ifdef BDE_DEBUGGER 142200Sdg .globl _bdb_exists /* flag to indicate BDE debugger is available */ 143134Sdg_bdb_exists: .long 0 1441321Sdg#endif 145757Sdg 1464Srgrimes/* 1471321Sdg * System Initialization 1484Srgrimes */ 1494Srgrimes .text 150556Srgrimes 1514Srgrimes/* 1524Srgrimes * btext: beginning of text section. 1534Srgrimes * Also the entry point (jumped to directly from the boot blocks). 1544Srgrimes */ 1554SrgrimesNON_GPROF_ENTRY(btext) 156570Srgrimes movw $0x1234,0x472 /* warm boot */ 1574Srgrimes 158570Srgrimes /* Set up a real frame, some day we will be doing returns */ 1594Srgrimes pushl %ebp 160570Srgrimes movl %esp, %ebp 161556Srgrimes 162570Srgrimes /* Don't trust what the BIOS gives for eflags. */ 163570Srgrimes pushl $PSL_KERNEL 164975Smartin popfl 165975Smartin 166975Smartin /* Don't trust what the BIOS gives for %fs and %gs. */ 167975Smartin mov %ds, %ax 1681688Sdg mov %ax, %fs 169975Smartin mov %ax, %gs 170975Smartin 171975Smartin /* 1724Srgrimes * This code is called in different ways depending on what loaded 1731998Swollman * and started the kernel. This is used to detect how we get the 1741321Sdg * arguments from the other code and what we do with them. 1751998Swollman * 1761998Swollman * Old disk boot blocks: 1771998Swollman * (*btext)(howto, bootdev, cyloffset, esym); 1781998Swollman * [return address == 0, and can NOT be returned to] 1791998Swollman * [cyloffset was not supported by the FreeBSD boot code 1801998Swollman * and always passed in as 0] 1811998Swollman * [esym is also known as total in the boot code, and 1821998Swollman * was never properly supported by the FreeBSD boot code] 1831998Swollman * 1841998Swollman * Old diskless netboot code: 1851998Swollman * (*btext)(0,0,0,0,&nfsdiskless,0,0,0); 1861998Swollman * [return address != 0, and can NOT be returned to] 1871998Swollman * If we are being booted by this code it will NOT work, 1881998Swollman * so we are just going to halt if we find this case. 1891998Swollman * 1901998Swollman * New uniform boot code: 1911998Swollman * (*btext)(howto, bootdev, 0, 0, 0, &bootinfo) 192556Srgrimes * [return address != 0, and can be returned to] 1931998Swollman * 1941998Swollman * There may seem to be a lot of wasted arguments in here, but 1951998Swollman * that is so the newer boot code can still load very old kernels 1961998Swollman * and old boot code can load new kernels. 1971998Swollman */ 1981998Swollman 1991998Swollman /* 2001998Swollman * The old style disk boot blocks fake a frame on the stack and 2011998Swollman * did an lret to get here. The frame on the stack has a return 2021998Swollman * address of 0. 2031998Swollman */ 2041998Swollman cmpl $0,4(%ebp) 2051998Swollman je 2f /* olddiskboot: */ 2061998Swollman 2071998Swollman /* 2081998Swollman * We have some form of return address, so this is either the 2091998Swollman * old diskless netboot code, or the new uniform code. That can 2101998Swollman * be detected by looking at the 5th argument, it if is 0 we 2111998Swollman * we are being booted by the new unifrom boot code. 2121998Swollman */ 2131998Swollman cmpl $0,24(%ebp) 2141998Swollman je 1f /* newboot: */ 2151998Swollman 2161998Swollman /* 2171998Swollman * Seems we have been loaded by the old diskless boot code, we 2181998Swollman * don't stand a chance of running as the diskless structure 2191998Swollman * changed considerably between the two, so just halt. 2201998Swollman */ 2211998Swollman hlt 2221998Swollman 2231998Swollman /* 2241998Swollman * We have been loaded by the new uniform boot code. 2251998Swollman * Lets check the bootinfo version, and if we do not understand 2261998Swollman * it we return to the loader with a status of 1 to indicate this error 2271998Swollman */ 2281998Swollman1: /* newboot: */ 2291998Swollman movl 28(%ebp),%ebx /* &bootinfo.version */ 2301998Swollman movl BI_VERSION(%ebx),%eax 2311998Swollman cmpl $1,%eax /* We only understand version 1 */ 2321998Swollman je 1f 2331998Swollman movl $1,%eax /* Return status */ 234556Srgrimes leave 235556Srgrimes ret 2364Srgrimes 2374Srgrimes1: 2384Srgrimes /* 2394Srgrimes * If we have a kernelname copy it in 2404Srgrimes */ 2414Srgrimes movl BI_KERNELNAME(%ebx),%esi 2424Srgrimes cmpl $0,%esi 2434Srgrimes je 2f /* No kernelname */ 2444Srgrimes movl $MAXPATHLEN,%ecx /* Brute force!!! */ 2454Srgrimes lea _kernelname-KERNBASE,%edi 2464Srgrimes cmpb $'/',(%esi) /* Make sure it starts with a slash */ 2474Srgrimes je 1f 2484Srgrimes movb $'/',(%edi) 2494Srgrimes incl %edi 250757Sdg decl %ecx 2514Srgrimes1: 252570Srgrimes cld 253570Srgrimes rep 254570Srgrimes movsb 255570Srgrimes 256974Sdg2: 257570Srgrimes /* 258570Srgrimes * Determine the size of the boot loader's copy of the bootinfo 2594Srgrimes * struct. This is impossible to do properly because old versions 260570Srgrimes * of the struct don't contain a size field and there are 2 old 261757Sdg * versions with the same version number. 2624Srgrimes */ 2631321Sdg movl $BI_ENDCOMMON,%ecx /* prepare for sizeless version */ 264757Sdg testl $RB_BOOTINFO,8(%ebp) /* bi_size (and bootinfo) valid? */ 2654Srgrimes je got_bi_size /* no, sizeless version */ 266757Sdg movl BI_SIZE(%ebx),%ecx 267570Srgrimesgot_bi_size: 268760Srgrimes 269757Sdg /* 2704Srgrimes * Copy the common part of the bootinfo struct 2714Srgrimes */ 2724Srgrimes movl %ebx,%esi 2734Srgrimes movl $_bootinfo-KERNBASE,%edi 274608Srgrimes cmpl $BOOTINFO_SIZE,%ecx 275974Sdg jbe got_common_bi_size 276974Sdg movl $BOOTINFO_SIZE,%ecx 277974Sdggot_common_bi_size: 278974Sdg cld 279757Sdg rep 280757Sdg movsb 281608Srgrimes 282757Sdg#ifdef NFS 283608Srgrimes /* 284757Sdg * If we have a nfs_diskless structure copy it in 285757Sdg */ 286974Sdg movl BI_NFS_DISKLESS(%ebx),%esi 287757Sdg cmpl $0,%esi 288757Sdg je 2f 289757Sdg lea _nfs_diskless-KERNBASE,%edi 290757Sdg movl $NFSDISKLESS_SIZE,%ecx 291757Sdg cld 292757Sdg rep 293570Srgrimes movsb 2944Srgrimes lea _nfs_diskless_valid-KERNBASE,%edi 295592Srgrimes movl $1,(%edi) 296592Srgrimes#endif 297592Srgrimes 298592Srgrimes /* 299592Srgrimes * The old style disk boot. 300592Srgrimes * (*btext)(howto, bootdev, cyloffset, esym); 3014Srgrimes * Note that the newer boot code just falls into here to pick 3024Srgrimes * up howto and bootdev, cyloffset and esym are no longer used 303570Srgrimes */ 3044Srgrimes2: /* olddiskboot: */ 3054Srgrimes movl 8(%ebp),%eax 3064Srgrimes movl %eax,_boothowto-KERNBASE 3074Srgrimes movl 12(%ebp),%eax 3084Srgrimes movl %eax,_bootdev-KERNBASE 3094Srgrimes 3104Srgrimes#if NAPM > 0 3114Srgrimes /* call APM BIOS driver setup (i386/apm/apm_setup.s) */ 312757Sdg call _apm_setup 313757Sdg#endif /* NAPM */ 314757Sdg 315757Sdg /* Find out our CPU type. */ 316757Sdg 317200Sdg /* Try to toggle alignment check flag; does not exist on 386. */ 318200Sdg pushfl 319200Sdg popl %eax 320757Sdg movl %eax,%ecx 3211549Srgrimes orl $PSL_AC,%eax 322757Sdg pushl %eax 323757Sdg popfl 3244Srgrimes pushfl 3254Srgrimes popl %eax 326757Sdg xorl %ecx,%eax 327757Sdg andl $PSL_AC,%eax 328757Sdg pushl %ecx 329757Sdg popfl 330757Sdg 331757Sdg testl %eax,%eax 332757Sdg jnz 1f 333757Sdg movl $CPU_386,_cpu-KERNBASE 334757Sdg jmp 2f 335757Sdg 336757Sdg1: /* Try to toggle identification flag; does not exist on early 486s. */ 337757Sdg pushfl 338757Sdg popl %eax 339757Sdg movl %eax,%ecx 340757Sdg xorl $PSL_ID,%eax 341757Sdg pushl %eax 3421321Sdg popfl 343757Sdg pushfl 344757Sdg popl %eax 345757Sdg xorl %ecx,%eax 346974Sdg andl $PSL_ID,%eax 347757Sdg pushl %ecx 348757Sdg popfl 3491549Srgrimes 350757Sdg testl %eax,%eax 351757Sdg jnz 1f 352757Sdg movl $CPU_486,_cpu-KERNBASE 353757Sdg 354757Sdg /* check for Cyrix 486DLC -- based on check routine */ 3551321Sdg /* documented in "Cx486SLC/e SMM Programmer's Guide" */ 3564Srgrimes xorw %dx,%dx 3574Srgrimes cmpw %dx,%dx # set flags to known state 358757Sdg pushfw 359757Sdg popw %cx # store flags in ecx 360757Sdg movw $0xffff,%ax 3611046Sdg movw $0x0004,%bx 362757Sdg divw %bx 3634Srgrimes pushfw 3644Srgrimes popw %ax 3654Srgrimes andw $0x08d5,%ax # mask off important bits 3664Srgrimes andw $0x08d5,%cx 367757Sdg cmpw %ax,%cx 368757Sdg 369757Sdg jnz 3f # if flags changed, Intel chip 370757Sdg 371757Sdg movl $CPU_486DLC,_cpu-KERNBASE # set CPU value for Cyrix 372757Sdg movl $0x69727943,_cpu_vendor-KERNBASE # store vendor string 373757Sdg movw $0x0078,_cpu_vendor-KERNBASE+4 3744Srgrimes 3754Srgrimes#ifndef CYRIX_CACHE_WORKS 3764Srgrimes /* Disable caching of the ISA hole only. */ 377757Sdg invd 3784Srgrimes movb $CCR0,%al # Configuration Register index (CCR0) 3794Srgrimes outb %al,$0x22 380757Sdg inb $0x23,%al 381757Sdg orb $(CCR0_NC1|CCR0_BARB),%al 382757Sdg movb %al,%ah 3834Srgrimes movb $CCR0,%al 384757Sdg outb %al,$0x22 385974Sdg movb %ah,%al 386757Sdg outb %al,$0x23 3874Srgrimes invd 3884Srgrimes#else /* CYRIX_CACHE_WORKS */ 3894Srgrimes /* Set cache parameters */ 390757Sdg invd # Start with guaranteed clean cache 391757Sdg movb $CCR0,%al # Configuration Register index (CCR0) 392757Sdg outb %al,$0x22 3934Srgrimes inb $0x23,%al 3944Srgrimes andb $~CCR0_NC0,%al 395757Sdg#ifndef CYRIX_CACHE_REALLY_WORKS 396757Sdg orb $(CCR0_NC1|CCR0_BARB),%al 397757Sdg#else 3984Srgrimes orb $CCR0_NC1,%al 399757Sdg#endif 4004Srgrimes movb %al,%ah 4014Srgrimes movb $CCR0,%al 402757Sdg outb %al,$0x22 4034Srgrimes movb %ah,%al 404570Srgrimes outb %al,$0x23 4054Srgrimes /* clear non-cacheable region 1 */ 4064Srgrimes movb $(NCR1+2),%al 4074Srgrimes outb %al,$0x22 4084Srgrimes movb $NCR_SIZE_0K,%al 4094Srgrimes outb %al,$0x23 410757Sdg /* clear non-cacheable region 2 */ 411570Srgrimes movb $(NCR2+2),%al 4124Srgrimes outb %al,$0x22 4134Srgrimes movb $NCR_SIZE_0K,%al 4141688Sdg outb %al,$0x23 415757Sdg /* clear non-cacheable region 3 */ 4164Srgrimes movb $(NCR3+2),%al 417570Srgrimes outb %al,$0x22 4184Srgrimes movb $NCR_SIZE_0K,%al 4194Srgrimes outb %al,$0x23 4204Srgrimes /* clear non-cacheable region 4 */ 421757Sdg movb $(NCR4+2),%al 422757Sdg outb %al,$0x22 4234Srgrimes movb $NCR_SIZE_0K,%al 424570Srgrimes outb %al,$0x23 4254Srgrimes /* enable caching in CR0 */ 426570Srgrimes movl %cr0,%eax 427757Sdg andl $~(CR0_CD|CR0_NW),%eax 4284Srgrimes movl %eax,%cr0 429570Srgrimes invd 4304Srgrimes#endif /* CYRIX_CACHE_WORKS */ 431570Srgrimes jmp 3f 4324Srgrimes 433570Srgrimes1: /* Use the `cpuid' instruction. */ 4344Srgrimes xorl %eax,%eax 4354Srgrimes .byte 0x0f,0xa2 # cpuid 0 4361688Sdg movl %eax,_cpu_high-KERNBASE # highest capability 437757Sdg movl %ebx,_cpu_vendor-KERNBASE # store vendor string 4384Srgrimes movl %edx,_cpu_vendor+4-KERNBASE 4394Srgrimes movl %ecx,_cpu_vendor+8-KERNBASE 4404Srgrimes movb $0,_cpu_vendor+12-KERNBASE 4414Srgrimes 4424Srgrimes movl $1,%eax 4434Srgrimes .byte 0x0f,0xa2 # cpuid 1 4444Srgrimes movl %eax,_cpu_id-KERNBASE # store cpu_id 4451321Sdg movl %edx,_cpu_feature-KERNBASE # store cpu_feature 4464Srgrimes rorl $8,%eax # extract family type 447592Srgrimes andl $15,%eax 448757Sdg cmpl $5,%eax 449570Srgrimes jae 1f 450757Sdg 451757Sdg /* less than Pentium; must be 486 */ 452757Sdg movl $CPU_486,_cpu-KERNBASE 453757Sdg jmp 3f 4544Srgrimes1: 455757Sdg /* a Pentium? */ 4564Srgrimes cmpl $5,%eax 4574Srgrimes jne 2f 458570Srgrimes movl $CPU_586,_cpu-KERNBASE 4594Srgrimes jmp 3f 460757Sdg2: 461757Sdg /* Greater than Pentium...call it a Pentium Pro */ 462592Srgrimes movl $CPU_686,_cpu-KERNBASE 463757Sdg3: 464757Sdg 465757Sdg /* 466757Sdg * Finished with old stack; load new %esp now instead of later so 467570Srgrimes * 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 * 471757Sdg * XXX - wdboot clears the bss after testing that this is safe. 472570Srgrimes * This is too wasteful - memory below 640K is scarce. The boot 473757Sdg * program should check: 4744Srgrimes * text+data <= &stack_variable - more_space_for_stack 475570Srgrimes * text+data+bss+pad+space_for_page_tables <= end_of_memory 476570Srgrimes * Oops, the gdt is in the carcass of the boot program so clearing 4774Srgrimes * the rest of memory is still not possible. 478757Sdg */ 4794Srgrimes movl $tmpstk-KERNBASE,%esp /* bootstrap stack end location */ 4804Srgrimes 481757Sdg/* 4824Srgrimes * Virtual address space of kernel: 4834Srgrimes * 4841321Sdg * text | data | bss | [syms] | page dir | proc0 kernel stack | usr stk map | Sysmap 485757Sdg * pages: 1 UPAGES (2) 1 NKPT (7) 4864Srgrimes */ 4874Srgrimes 4884Srgrimes/* find end of kernel image */ 4894Srgrimes movl $_end-KERNBASE,%ecx 4904Srgrimes addl $NBPG-1,%ecx /* page align up */ 4914Srgrimes andl $~(NBPG-1),%ecx 4921321Sdg movl %ecx,%esi /* esi = start of free memory */ 4934Srgrimes movl %ecx,_KERNend-KERNBASE /* save end of kernel */ 494608Srgrimes 495608Srgrimes/* clear bss */ 496608Srgrimes movl $_edata-KERNBASE,%edi 497974Sdg subl %edi,%ecx /* get amount to clear */ 498608Srgrimes xorl %eax,%eax /* specify zero fill */ 499757Sdg cld 500757Sdg rep 5011549Srgrimes stosb 502200Sdg 5031549Srgrimes#ifdef DDB 5044Srgrimes/* include symbols in "kernel image" if they are loaded */ 5051549Srgrimes movl _bootinfo+BI_ESYMTAB-KERNBASE,%edi 5061549Srgrimes testl %edi,%edi 5071549Srgrimes je over_symalloc 5081549Srgrimes addl $NBPG-1,%edi 5091549Srgrimes andl $~(NBPG-1),%edi 5101549Srgrimes movl %edi,%esi 5111549Srgrimes movl %esi,_KERNend-KERNBASE 5121549Srgrimes movl $KERNBASE,%edi 5131549Srgrimes addl %edi,_bootinfo+BI_SYMTAB-KERNBASE 5141549Srgrimes addl %edi,_bootinfo+BI_ESYMTAB-KERNBASE 5151549Srgrimesover_symalloc: 5161549Srgrimes#endif 5171549Srgrimes 518757Sdg/* 5194Srgrimes * The value in esi is both the end of the kernel bss and a pointer to 5201549Srgrimes * the kernel page directory, and is used by the rest of locore to build 5211549Srgrimes * the tables. 522134Sdg * esi + 1(page dir) + 2(UPAGES) + 1(p0stack) + NKPT(number of kernel 523570Srgrimes * page table pages) is then passed on the stack to init386(first) as 524570Srgrimes * the value first. esi should ALWAYS be page aligned!! 5251058Sdg */ 5261058Sdg movl %esi,%ecx /* Get current first availiable address */ 5271058Sdg 5281058Sdg/* clear pagetables, page directory, stack, etc... */ 5291058Sdg movl %esi,%edi /* base (page directory) */ 5301058Sdg movl $((1+UPAGES+1+NKPT)*NBPG),%ecx /* amount to clear */ 5311058Sdg xorl %eax,%eax /* specify zero fill */ 5321058Sdg cld 5331058Sdg rep 534134Sdg stosb 535134Sdg 536134Sdg/* physical address of Idle proc/kernel page directory */ 5371058Sdg movl %esi,_IdlePTD-KERNBASE 5384Srgrimes 5394Srgrimes/* 5401549Srgrimes * fillkpt 5414Srgrimes * eax = (page frame address | control | status) == pte 5424Srgrimes * ebx = address of page table 543757Sdg * ecx = how many pages to map 544757Sdg */ 5451549Srgrimes#define fillkpt \ 5464Srgrimes1: movl %eax,(%ebx) ; \ 5471549Srgrimes addl $NBPG,%eax ; /* increment physical address */ \ 5484Srgrimes addl $4,%ebx ; /* next pte */ \ 549200Sdg loop 1b ; 550592Srgrimes 551757Sdg/* 552757Sdg * Map Kernel 5534Srgrimes * 554757Sdg * First step - build page tables 555757Sdg */ 556757Sdg#if defined (KGDB) || defined (BDE_DEBUGGER) 557757Sdg movl _KERNend-KERNBASE,%ecx /* this much memory, */ 5584Srgrimes shrl $PGSHIFT,%ecx /* for this many PTEs */ 5594Srgrimes#ifdef BDE_DEBUGGER 5604Srgrimes cmpl $0xa0,%ecx /* XXX - cover debugger pages */ 5614Srgrimes jae 1f 562 movl $0xa0,%ecx 5631: 564#endif /* BDE_DEBUGGER */ 565 movl $PG_V|PG_KW,%eax /* kernel R/W, valid */ 566 lea ((1+UPAGES+1)*NBPG)(%esi),%ebx /* phys addr of kernel PT base */ 567 movl %ebx,_KPTphys-KERNBASE /* save in global */ 568 fillkpt 569 570#else /* !KGDB && !BDE_DEBUGGER */ 571 /* write protect kernel text (doesn't do a thing for 386's - only 486's) */ 572 movl $_etext-KERNBASE,%ecx /* get size of text */ 573 addl $NBPG-1,%ecx /* round up to page */ 574 shrl $PGSHIFT,%ecx /* for this many PTEs */ 575 movl $PG_V|PG_KR,%eax /* specify read only */ 576#if 0 577 movl $_etext,%ecx /* get size of text */ 578 subl $_btext,%ecx 579 addl $NBPG-1,%ecx /* round up to page */ 580 shrl $PGSHIFT,%ecx /* for this many PTEs */ 581 movl $_btext-KERNBASE,%eax /* get offset to physical memory */ 582 orl $PG_V|PG_KR,%eax /* specify read only */ 583#endif 584 lea ((1+UPAGES+1)*NBPG)(%esi),%ebx /* phys addr of kernel PT base */ 585 movl %ebx,_KPTphys-KERNBASE /* save in global */ 586 fillkpt 587 588 /* data and bss are r/w */ 589 andl $PG_FRAME,%eax /* strip to just addr of bss */ 590 movl _KERNend-KERNBASE,%ecx /* calculate size */ 591 subl %eax,%ecx 592 shrl $PGSHIFT,%ecx 593 orl $PG_V|PG_KW,%eax /* valid, kernel read/write */ 594 fillkpt 595#endif /* KGDB || BDE_DEBUGGER */ 596 597/* now initialize the page dir, upages, and p0stack PT */ 598 599 movl $(1+UPAGES+1),%ecx /* number of PTEs */ 600 movl %esi,%eax /* phys address of PTD */ 601 andl $PG_FRAME,%eax /* convert to PFN, should be a NOP */ 602 orl $PG_V|PG_KW,%eax /* valid, kernel read/write */ 603 movl %esi,%ebx /* calculate pte offset to ptd */ 604 shrl $PGSHIFT-2,%ebx 605 addl %esi,%ebx /* address of page directory */ 606 addl $((1+UPAGES+1)*NBPG),%ebx /* offset to kernel page tables */ 607 fillkpt 608 609/* map I/O memory map */ 610 611 movl _KPTphys-KERNBASE,%ebx /* base of kernel page tables */ 612 lea (0xa0 * PTESIZE)(%ebx),%ebx /* hardwire ISA hole at KERNBASE + 0xa0000 */ 613 movl $0x100-0xa0,%ecx /* for this many pte s, */ 614 movl $(0xa0000|PG_V|PG_KW|PG_N),%eax /* valid, kernel read/write, non-cacheable */ 615 movl %ebx,_atdevphys-KERNBASE /* save phys addr of ptes */ 616 fillkpt 617 618 /* map proc 0's kernel stack into user page table page */ 619 620 movl $UPAGES,%ecx /* for this many pte s, */ 621 lea (1*NBPG)(%esi),%eax /* physical address in proc 0 */ 622 lea (KERNBASE)(%eax),%edx /* change into virtual addr */ 623 movl %edx,_proc0paddr-KERNBASE /* save VA for proc 0 init */ 624 orl $PG_V|PG_KW,%eax /* valid, kernel read/write */ 625 lea ((1+UPAGES)*NBPG)(%esi),%ebx /* addr of stack page table in proc 0 */ 626 addl $(KSTKPTEOFF * PTESIZE),%ebx /* offset to kernel stack PTE */ 627 fillkpt 628 629/* 630 * Initialize kernel page table directory 631 */ 632 /* install a pde for temporary double map of bottom of VA */ 633 movl _KPTphys-KERNBASE,%eax 634 orl $PG_V|PG_KW,%eax /* valid, kernel read/write */ 635 movl %eax,(%esi) /* which is where temp maps! */ 636 637 /* initialize kernel pde's */ 638 movl $(NKPT),%ecx /* for this many PDEs */ 639 lea (KPTDI*PDESIZE)(%esi),%ebx /* offset of pde for kernel */ 640 fillkpt 641 642 /* install a pde recursively mapping page directory as a page table! */ 643 movl %esi,%eax /* phys address of ptd in proc 0 */ 644 orl $PG_V|PG_KW,%eax /* pde entry is valid */ 645 movl %eax,PTDPTDI*PDESIZE(%esi) /* which is where PTmap maps! */ 646 647 /* install a pde to map kernel stack for proc 0 */ 648 lea ((1+UPAGES)*NBPG)(%esi),%eax /* physical address of pt in proc 0 */ 649 orl $PG_V|PG_KW,%eax /* pde entry is valid */ 650 movl %eax,KSTKPTDI*PDESIZE(%esi) /* which is where kernel stack maps! */ 651 652#ifdef BDE_DEBUGGER 653 /* copy and convert stuff from old gdt and idt for debugger */ 654 655 cmpl $0x0375c339,0x96104 /* XXX - debugger signature */ 656 jne 1f 657 movb $1,_bdb_exists-KERNBASE 6581: 659 pushal 660 subl $2*6,%esp 661 662 sgdt (%esp) 663 movl 2(%esp),%esi /* base address of current gdt */ 664 movl $_gdt-KERNBASE,%edi 665 movl %edi,2(%esp) 666 movl $8*18/4,%ecx 667 cld 668 rep /* copy gdt */ 669 movsl 670 movl $_gdt-KERNBASE,-8+2(%edi) /* adjust gdt self-ptr */ 671 movb $0x92,-8+5(%edi) 672 673 sidt 6(%esp) 674 movl 6+2(%esp),%esi /* base address of current idt */ 675 movl 8+4(%esi),%eax /* convert dbg descriptor to ... */ 676 movw 8(%esi),%ax 677 movl %eax,bdb_dbg_ljmp+1-KERNBASE /* ... immediate offset ... */ 678 movl 8+2(%esi),%eax 679 movw %ax,bdb_dbg_ljmp+5-KERNBASE /* ... and selector for ljmp */ 680 movl 24+4(%esi),%eax /* same for bpt descriptor */ 681 movw 24(%esi),%ax 682 movl %eax,bdb_bpt_ljmp+1-KERNBASE 683 movl 24+2(%esi),%eax 684 movw %ax,bdb_bpt_ljmp+5-KERNBASE 685 686 movl $_idt-KERNBASE,%edi 687 movl %edi,6+2(%esp) 688 movl $8*4/4,%ecx 689 cld 690 rep /* copy idt */ 691 movsl 692 693 lgdt (%esp) 694 lidt 6(%esp) 695 696 addl $2*6,%esp 697 popal 698#endif /* BDE_DEBUGGER */ 699 700 /* load base of page directory and enable mapping */ 701 movl %esi,%eax /* phys address of ptd in proc 0 */ 702 movl %eax,%cr3 /* load ptd addr into mmu */ 703 movl %cr0,%eax /* get control word */ 704 orl $CR0_PE|CR0_PG,%eax /* enable paging */ 705 movl %eax,%cr0 /* and let's page NOW! */ 706 707 pushl $begin /* jump to high mem */ 708 ret 709 710begin: /* now running relocated at KERNBASE where the system is linked to run */ 711 movl _atdevphys,%edx /* get pte PA */ 712 subl _KPTphys,%edx /* remove base of ptes, now have phys offset */ 713 shll $PGSHIFT-2,%edx /* corresponding to virt offset */ 714 addl $KERNBASE,%edx /* add virtual base */ 715 movl %edx,_atdevbase 716 717 /* set up bootstrap stack */ 718 movl $_kstack+UPAGES*NBPG,%esp /* bootstrap stack end location */ 719 xorl %eax,%eax /* mark end of frames */ 720 movl %eax,%ebp 721 movl _proc0paddr,%eax 722 movl %esi,PCB_CR3(%eax) 723 724#ifdef BDE_DEBUGGER 725 /* relocate debugger gdt entries */ 726 727 movl $_gdt+8*9,%eax /* adjust slots 9-17 */ 728 movl $9,%ecx 729reloc_gdt: 730 movb $KERNBASE>>24,7(%eax) /* top byte of base addresses, was 0, */ 731 addl $8,%eax /* now KERNBASE>>24 */ 732 loop reloc_gdt 733 734 cmpl $0,_bdb_exists 735 je 1f 736 int $3 7371: 738#endif /* BDE_DEBUGGER */ 739 740 /* 741 * Prepare "first" - physical address of first available page 742 * after the kernel+pdir+upages+p0stack+page tables 743 */ 744 lea ((1+UPAGES+1+NKPT)*NBPG)(%esi),%esi 745 746 pushl %esi /* value of first for init386(first) */ 747 call _init386 /* wire 386 chip for unix operation */ 748 popl %esi 749 750 .globl __ucodesel,__udatasel 751 752 pushl $0 /* unused */ 753 pushl __udatasel /* ss */ 754 pushl $0 /* esp - filled in by execve() */ 755 pushl $PSL_USER /* eflags (IOPL 0, int enab) */ 756 pushl __ucodesel /* cs */ 757 pushl $0 /* eip - filled in by execve() */ 758 subl $(12*4),%esp /* space for rest of registers */ 759 760 pushl %esp /* call main with frame pointer */ 761 call _main /* autoconfiguration, mountroot etc */ 762 763 addl $(13*4),%esp /* back to a frame we can return with */ 764 765 /* 766 * now we've run main() and determined what cpu-type we are, we can 767 * enable write protection and alignment checking on i486 cpus and 768 * above. 769 */ 770#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU) 771 cmpl $CPUCLASS_386,_cpu_class 772 je 1f 773 movl %cr0,%eax /* get control word */ 774 orl $CR0_WP|CR0_AM,%eax /* enable i486 features */ 775 movl %eax,%cr0 /* and do it */ 776#endif 777 /* 778 * on return from main(), we are process 1 779 * set up address space and stack so that we can 'return' to user mode 780 */ 7811: 782 movl __ucodesel,%eax 783 movl __udatasel,%ecx 784 785 movl %cx,%ds 786 movl %cx,%es 787 movl %ax,%fs /* double map cs to fs */ 788 movl %cx,%gs /* and ds to gs */ 789 iret /* goto user! */ 790 791#define LCALL(x,y) .byte 0x9a ; .long y ; .word x 792 793NON_GPROF_ENTRY(sigcode) 794 call SIGF_HANDLER(%esp) 795 lea SIGF_SC(%esp),%eax /* scp (the call may have clobbered the */ 796 /* copy at 8(%esp)) */ 797 pushl %eax 798 pushl %eax /* junk to fake return address */ 799 movl $103,%eax /* XXX sigreturn() */ 800 LCALL(0x7,0) /* enter kernel with args on stack */ 801 hlt /* never gets here */ 802 803 .globl _szsigcode 804_szsigcode: 805 .long _szsigcode-_sigcode 806