locore.s revision 1549
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 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * from: @(#)locore.s 7.3 (Berkeley) 5/13/91 37 * $Id: locore.s,v 1.15 1994/02/01 04:08:54 davidg Exp $ 38 */ 39 40/* 41 * locore.s: FreeBSD machine support for the Intel 386 42 * originally from: locore.s, by William F. Jolitz 43 * 44 * Substantially rewritten by David Greenman, Rod Grimes, 45 * Bruce Evans, Wolfgang Solfrank, and many others. 46 */ 47 48#include "npx.h" /* for NNPX */ 49#include "assym.s" /* system definitions */ 50#include "machine/psl.h" /* processor status longword defs */ 51#include "machine/pte.h" /* page table entry definitions */ 52#include "errno.h" /* error return codes */ 53#include "machine/specialreg.h" /* x86 special registers */ 54#include "machine/cputypes.h" /* x86 cpu type definitions */ 55#include "syscall.h" /* system call numbers */ 56#include "machine/asmacros.h" /* miscellaneous asm macros */ 57 58/* 59 * XXX 60 * 61 * Note: This version greatly munged to avoid various assembler errors 62 * that may be fixed in newer versions of gas. Perhaps newer versions 63 * will have more pleasant appearance. 64 */ 65 66/* 67 * PTmap is recursive pagemap at top of virtual address space. 68 * Within PTmap, the page directory can be found (third indirection). 69 */ 70 .globl _PTmap,_PTD,_PTDpde,_Sysmap 71 .set _PTmap,PTDPTDI << PDRSHIFT 72 .set _PTD,_PTmap + (PTDPTDI * NBPG) 73 .set _PTDpde,_PTD + (PTDPTDI * PDESIZE) 74 75/* Sysmap is the base address of the kernel page tables */ 76 .set _Sysmap,_PTmap + (KPTDI * NBPG) 77 78/* 79 * APTmap, APTD is the alternate recursive pagemap. 80 * It's used when modifying another process's page tables. 81 */ 82 .globl _APTmap,_APTD,_APTDpde 83 .set _APTmap,APTDPTDI << PDRSHIFT 84 .set _APTD,_APTmap + (APTDPTDI * NBPG) 85 .set _APTDpde,_PTD + (APTDPTDI * PDESIZE) 86 87/* 88 * Access to each processes kernel stack is via a region of 89 * per-process address space (at the beginning), immediatly above 90 * the user process stack. 91 */ 92 .set _kstack,USRSTACK 93 .globl _kstack 94 95/* 96 * Globals 97 */ 98 .data 99 .globl _esym 100_esym: .long 0 /* ptr to end of syms */ 101 102 .globl _boothowto,_bootdev,_curpcb 103 104 .globl _cpu,_cold,_atdevbase 105_cpu: .long 0 /* are we 386, 386sx, or 486 */ 106_cold: .long 1 /* cold till we are not */ 107_atdevbase: .long 0 /* location of start of iomem in virtual */ 108_atdevphys: .long 0 /* location of device mapping ptes (phys) */ 109 110 .globl _KERNend 111_KERNend: .long 0 /* phys addr end of kernel (just after bss) */ 112 113 .globl _IdlePTD,_KPTphys 114_IdlePTD: .long 0 /* phys addr of kernel PTD */ 115_KPTphys: .long 0 /* phys addr of kernel page tables */ 116 117 .globl _cyloffset 118_cyloffset: .long 0 /* cylinder offset from boot blocks */ 119 120 .globl _proc0paddr 121_proc0paddr: .long 0 /* address of proc 0 address space */ 122 123#ifdef BDE_DEBUGGER 124 .globl _bdb_exists /* flag to indicate BDE debugger is available */ 125_bdb_exists: .long 0 126#endif 127 128 .globl tmpstk 129 .space 0x1000 130tmpstk: 131 132 133/* 134 * System Initialization 135 */ 136 .text 137 138/* 139 * btext: beginning of text section. 140 * Also the entry point (jumped to directly from the boot blocks). 141 */ 142NON_GPROF_ENTRY(btext) 143 movw $0x1234,0x472 /* warm boot */ 144 jmp 1f 145 .org 0x500 /* space for BIOS variables */ 146 147 /* 148 * pass parameters on stack (howto, bootdev, unit, cyloffset, esym) 149 * note: (%esp) is return address of boot 150 * ( if we want to hold onto /boot, it's physical %esp up to _end) 151 */ 152 153 1: movl 4(%esp),%eax 154 movl %eax,_boothowto-KERNBASE 155 movl 8(%esp),%eax 156 movl %eax,_bootdev-KERNBASE 157 movl 12(%esp),%eax 158 movl %eax,_cyloffset-KERNBASE 159 movl 16(%esp),%eax 160 addl $KERNBASE,%eax 161 movl %eax,_esym-KERNBASE 162#ifdef DISKLESS /* Copy diskless structure */ 163 movl _nfs_diskless_size-KERNBASE,%ecx 164 movl 20(%esp),%esi 165 movl $(_nfs_diskless-KERNBASE),%edi 166 rep 167 movsb 168#endif 169 170 /* find out our CPU type. */ 171 pushfl 172 popl %eax 173 movl %eax,%ecx 174 xorl $0x40000,%eax 175 pushl %eax 176 popfl 177 pushfl 178 popl %eax 179 xorl %ecx,%eax 180 shrl $18,%eax 181 andl $1,%eax 182 push %ecx 183 popfl 184 185 cmpl $0,%eax 186 jne 1f 187 movl $CPU_386,_cpu-KERNBASE 188 jmp 2f 1891: movl $CPU_486,_cpu-KERNBASE 1902: 191 192 /* 193 * Finished with old stack; load new %esp now instead of later so 194 * we can trace this code without having to worry about the trace 195 * trap clobbering the memory test or the zeroing of the bss+bootstrap 196 * page tables. 197 * 198 * XXX - wdboot clears the bss after testing that this is safe. 199 * This is too wasteful - memory below 640K is scarce. The boot 200 * program should check: 201 * text+data <= &stack_variable - more_space_for_stack 202 * text+data+bss+pad+space_for_page_tables <= end_of_memory 203 * Oops, the gdt is in the carcass of the boot program so clearing 204 * the rest of memory is still not possible. 205 */ 206 movl $tmpstk-KERNBASE,%esp /* bootstrap stack end location */ 207 208/* 209 * Virtual address space of kernel: 210 * 211 * text | data | bss | [syms] | page dir | proc0 kernel stack | usr stk map | Sysmap 212 * pages: 1 UPAGES (2) 1 NKPT (7) 213 */ 214 215/* find end of kernel image */ 216 movl $_end-KERNBASE,%ecx 217 addl $NBPG-1,%ecx /* page align up */ 218 andl $~(NBPG-1),%ecx 219 movl %ecx,%esi /* esi = start of free memory */ 220 movl %ecx,_KERNend-KERNBASE /* save end of kernel */ 221 222/* clear bss */ 223 movl $_edata-KERNBASE,%edi 224 subl %edi,%ecx /* get amount to clear */ 225 xorl %eax,%eax /* specify zero fill */ 226 cld 227 rep 228 stosb 229 230/* 231 * The value in esi is both the end of the kernel bss and a pointer to 232 * the kernel page directory, and is used by the rest of locore to build 233 * the tables. 234 * esi + 1(page dir) + 2(UPAGES) + 1(p0stack) + NKPT(number of kernel 235 * page table pages) is then passed on the stack to init386(first) as 236 * the value first. esi should ALWAYS be page aligned!! 237 */ 238 movl %esi,%ecx /* Get current first availiable address */ 239 240/* clear pagetables, page directory, stack, etc... */ 241 movl %esi,%edi /* base (page directory) */ 242 movl $((1+UPAGES+1+NKPT)*NBPG),%ecx /* amount to clear */ 243 xorl %eax,%eax /* specify zero fill */ 244 cld 245 rep 246 stosb 247 248/* physical address of Idle proc/kernel page directory */ 249 movl %esi,_IdlePTD-KERNBASE 250 251/* 252 * fillkpt 253 * eax = (page frame address | control | status) == pte 254 * ebx = address of page table 255 * ecx = how many pages to map 256 */ 257#define fillkpt \ 2581: movl %eax,(%ebx) ; \ 259 addl $NBPG,%eax ; /* increment physical address */ \ 260 addl $4,%ebx ; /* next pte */ \ 261 loop 1b ; 262 263/* 264 * Map Kernel 265 * 266 * First step - build page tables 267 */ 268#if defined (KGDB) || defined (BDE_DEBUGGER) 269 movl _KERNend-KERNBASE,%ecx /* this much memory, */ 270 shrl $PGSHIFT,%ecx /* for this many PTEs */ 271#ifdef BDE_DEBUGGER 272 cmpl $0xa0,%ecx /* XXX - cover debugger pages */ 273 jae 1f 274 movl $0xa0,%ecx 2751: 276#endif /* BDE_DEBUGGER */ 277 movl $PG_V|PG_KW|PG_NC_PWT,%eax /* kernel R/W, valid, cache write-through */ 278 lea ((1+UPAGES+1)*NBPG)(%esi),%ebx /* phys addr of kernel PT base */ 279 movl %ebx,_KPTphys-KERNBASE /* save in global */ 280 fillkpt 281 282#else /* !KGDB && !BDE_DEBUGGER */ 283 /* write protect kernel text (doesn't do a thing for 386's - only 486's) */ 284 movl $_etext-KERNBASE,%ecx /* get size of text */ 285 shrl $PGSHIFT,%ecx /* for this many PTEs */ 286 movl $PG_V|PG_KR,%eax /* specify read only */ 287 lea ((1+UPAGES+1)*NBPG)(%esi),%ebx /* phys addr of kernel PT base */ 288 movl %ebx,_KPTphys-KERNBASE /* save in global */ 289 fillkpt 290 291 /* data and bss are r/w */ 292 andl $PG_FRAME,%eax /* strip to just addr of bss */ 293 movl _KERNend-KERNBASE,%ecx /* calculate size */ 294 subl %eax,%ecx 295 shrl $PGSHIFT,%ecx 296 orl $PG_V|PG_KW,%eax /* valid, kernel read/write */ 297 fillkpt 298#endif /* KGDB || BDE_DEBUGGER */ 299 300/* now initialize the page dir, upages, p0stack PT, and page tables */ 301 302 movl $(1+UPAGES+1+NKPT),%ecx /* number of PTEs */ 303 movl %esi,%eax /* phys address of PTD */ 304 andl $PG_FRAME,%eax /* convert to PFN, should be a NOP */ 305 orl $PG_V|PG_KW|PG_NC_PWT,%eax /* valid, kernel read/write, cache write-though */ 306 movl %esi,%ebx /* calculate pte offset to ptd */ 307 shrl $PGSHIFT-2,%ebx 308 addl %esi,%ebx /* address of page directory */ 309 addl $((1+UPAGES+1)*NBPG),%ebx /* offset to kernel page tables */ 310 fillkpt 311 312/* map I/O memory map */ 313 314 movl _KPTphys-KERNBASE,%ebx /* base of kernel page tables */ 315 lea (0xa0 * PTESIZE)(%ebx),%ebx /* hardwire ISA hole at KERNBASE + 0xa0000 */ 316 movl $0x100-0xa0,%ecx /* for this many pte s, */ 317 movl $(0xa0000|PG_V|PG_KW|PG_N),%eax /* valid, kernel read/write, non-cacheable */ 318 movl %ebx,_atdevphys-KERNBASE /* save phys addr of ptes */ 319 fillkpt 320 321 /* map proc 0's kernel stack into user page table page */ 322 323 movl $UPAGES,%ecx /* for this many pte s, */ 324 lea (1*NBPG)(%esi),%eax /* physical address in proc 0 */ 325 lea (KERNBASE)(%eax),%edx /* change into virtual addr */ 326 movl %edx,_proc0paddr-KERNBASE /* save VA for proc 0 init */ 327 orl $PG_V|PG_KW,%eax /* valid, kernel read/write */ 328 lea ((1+UPAGES)*NBPG)(%esi),%ebx /* addr of stack page table in proc 0 */ 329 addl $(KSTKPTEOFF * PTESIZE),%ebx /* offset to kernel stack PTE */ 330 fillkpt 331 332/* 333 * Initialize kernel page table directory 334 */ 335 /* install a pde for temporary double map of bottom of VA */ 336 movl _KPTphys-KERNBASE,%eax 337 orl $PG_V|PG_KW,%eax /* valid, kernel read/write */ 338 movl %eax,(%esi) /* which is where temp maps! */ 339 340 /* initialize kernel pde's */ 341 movl $(NKPT),%ecx /* for this many PDEs */ 342 lea (KPTDI*PDESIZE)(%esi),%ebx /* offset of pde for kernel */ 343 fillkpt 344 345 /* install a pde recursively mapping page directory as a page table! */ 346 movl %esi,%eax /* phys address of ptd in proc 0 */ 347 orl $PG_V|PG_KW,%eax /* pde entry is valid */ 348 movl %eax,PTDPTDI*PDESIZE(%esi) /* which is where PTmap maps! */ 349 350 /* install a pde to map kernel stack for proc 0 */ 351 lea ((1+UPAGES)*NBPG)(%esi),%eax /* physical address of pt in proc 0 */ 352 orl $PG_V|PG_KW,%eax /* pde entry is valid */ 353 movl %eax,KSTKPTDI*PDESIZE(%esi) /* which is where kernel stack maps! */ 354 355#ifdef BDE_DEBUGGER 356 /* copy and convert stuff from old gdt and idt for debugger */ 357 358 cmpl $0x0375c339,0x96104 /* XXX - debugger signature */ 359 jne 1f 360 movb $1,_bdb_exists-KERNBASE 3611: 362 pushal 363 subl $2*6,%esp 364 365 sgdt (%esp) 366 movl 2(%esp),%esi /* base address of current gdt */ 367 movl $_gdt-KERNBASE,%edi 368 movl %edi,2(%esp) 369 movl $8*18/4,%ecx 370 rep /* copy gdt */ 371 movsl 372 movl $_gdt-KERNBASE,-8+2(%edi) /* adjust gdt self-ptr */ 373 movb $0x92,-8+5(%edi) 374 375 sidt 6(%esp) 376 movl 6+2(%esp),%esi /* base address of current idt */ 377 movl 8+4(%esi),%eax /* convert dbg descriptor to ... */ 378 movw 8(%esi),%ax 379 movl %eax,bdb_dbg_ljmp+1-KERNBASE /* ... immediate offset ... */ 380 movl 8+2(%esi),%eax 381 movw %ax,bdb_dbg_ljmp+5-KERNBASE /* ... and selector for ljmp */ 382 movl 24+4(%esi),%eax /* same for bpt descriptor */ 383 movw 24(%esi),%ax 384 movl %eax,bdb_bpt_ljmp+1-KERNBASE 385 movl 24+2(%esi),%eax 386 movw %ax,bdb_bpt_ljmp+5-KERNBASE 387 388 movl $_idt-KERNBASE,%edi 389 movl %edi,6+2(%esp) 390 movl $8*4/4,%ecx 391 rep /* copy idt */ 392 movsl 393 394 lgdt (%esp) 395 lidt 6(%esp) 396 397 addl $2*6,%esp 398 popal 399#endif /* BDE_DEBUGGER */ 400 401 /* load base of page directory and enable mapping */ 402 movl %esi,%eax /* phys address of ptd in proc 0 */ 403 orl $I386_CR3PAT,%eax 404 movl %eax,%cr3 /* load ptd addr into mmu */ 405 movl %cr0,%eax /* get control word */ 406 orl $CR0_PE|CR0_PG,%eax /* enable paging */ 407 movl %eax,%cr0 /* and let's page NOW! */ 408 409 pushl $begin /* jump to high mem */ 410 ret 411 412begin: /* now running relocated at KERNBASE where the system is linked to run */ 413 414 .globl _Crtat /* XXX - locore should not know about */ 415 movl _Crtat,%eax /* variables of device drivers (pccons)! */ 416 subl $(KERNBASE+0xA0000),%eax 417 movl _atdevphys,%edx /* get pte PA */ 418 subl _KPTphys,%edx /* remove base of ptes, now have phys offset */ 419 shll $PGSHIFT-2,%edx /* corresponding to virt offset */ 420 addl $KERNBASE,%edx /* add virtual base */ 421 movl %edx,_atdevbase 422 addl %eax,%edx 423 movl %edx,_Crtat 424 425 /* set up bootstrap stack - 48 bytes */ 426 movl $_kstack+UPAGES*NBPG-4*12,%esp /* bootstrap stack end location */ 427 xorl %eax,%eax /* mark end of frames */ 428 movl %eax,%ebp 429 movl _proc0paddr,%eax 430 movl %esi,PCB_CR3(%eax) 431 432#ifdef BDE_DEBUGGER 433 /* relocate debugger gdt entries */ 434 435 movl $_gdt+8*9,%eax /* adjust slots 9-17 */ 436 movl $9,%ecx 437reloc_gdt: 438 movb $KERNBASE>>24,7(%eax) /* top byte of base addresses, was 0, */ 439 addl $8,%eax /* now KERNBASE>>24 */ 440 loop reloc_gdt 441 442 cmpl $0,_bdb_exists 443 je 1f 444 int $3 4451: 446#endif /* BDE_DEBUGGER */ 447 448 /* 449 * Skip over the page tables and the kernel stack 450 */ 451 lea ((1+UPAGES+1+NKPT)*NBPG)(%esi),%esi 452 453 pushl %esi /* value of first for init386(first) */ 454 call _init386 /* wire 386 chip for unix operation */ 455 popl %esi 456 457#if 0 458 movl $0,_PTD 459#endif 460 461 .globl __ucodesel,__udatasel 462 463 pushl $0 /* unused */ 464 pushl __udatasel /* ss */ 465 pushl $0 /* esp - filled in by execve() */ 466 pushl $0x3200 /* eflags (ring 3, int enab) */ 467 pushl __ucodesel /* cs */ 468 pushl $0 /* eip - filled in by execve() */ 469 subl $(12*4),%esp /* space for rest of registers */ 470 471 pushl %esp /* call main with frame pointer */ 472 call _main /* autoconfiguration, mountroot etc */ 473 474 addl $(13*4),%esp /* back to a frame we can return with */ 475 476 /* 477 * now we've run main() and determined what cpu-type we are, we can 478 * enable WP mode on i486 cpus and above. 479 */ 480#if defined(I486_CPU) || defined(I586_CPU) 481 cmpl $CPUCLASS_386,_cpu_class 482 je 1f 483 movl %cr0,%eax /* get control word */ 484 orl $CR0_WP,%eax /* enable write protect for all modes */ 485 movl %eax,%cr0 /* and do it */ 486#endif 487 /* 488 * on return from main(), we are process 1 489 * set up address space and stack so that we can 'return' to user mode 490 */ 4911: 492 movl __ucodesel,%eax 493 movl __udatasel,%ecx 494 495 movl %cx,%ds 496 movl %cx,%es 497 movl %ax,%fs /* double map cs to fs */ 498 movl %cx,%gs /* and ds to gs */ 499 iret /* goto user! */ 500 501#define LCALL(x,y) .byte 0x9a ; .long y ; .word x 502 503NON_GPROF_ENTRY(sigcode) 504 call SIGF_HANDLER(%esp) 505 lea SIGF_SC(%esp),%eax /* scp (the call may have clobbered the */ 506 /* copy at 8(%esp)) */ 507 pushl %eax 508 pushl %eax /* junk to fake return address */ 509 movl $103,%eax /* XXX sigreturn() */ 510 LCALL(0x7,0) /* enter kernel with args on stack */ 511 hlt /* never gets here */ 512 513 .globl _szsigcode 514_szsigcode: 515 .long _szsigcode-_sigcode 516