locore.s revision 3842
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.38 1994/10/22 17:51:46 phk 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 <sys/errno.h> /* error return codes */ 53#include <machine/specialreg.h> /* x86 special registers */ 54#include <machine/cputypes.h> /* x86 cpu type definitions */ 55#include <sys/syscall.h> /* system call numbers */ 56#include <machine/asmacros.h> /* miscellaneous asm macros */ 57#include "apm.h" 58#if NAPM > 0 59#define ASM 60#include <machine/apm_bios.h> 61#include <machine/apm_segments.h> 62#endif /* NAPM */ 63 64/* 65 * XXX 66 * 67 * Note: This version greatly munged to avoid various assembler errors 68 * that may be fixed in newer versions of gas. Perhaps newer versions 69 * will have more pleasant appearance. 70 */ 71 72/* 73 * PTmap is recursive pagemap at top of virtual address space. 74 * Within PTmap, the page directory can be found (third indirection). 75 */ 76 .globl _PTmap,_PTD,_PTDpde,_Sysmap 77 .set _PTmap,PTDPTDI << PDRSHIFT 78 .set _PTD,_PTmap + (PTDPTDI * NBPG) 79 .set _PTDpde,_PTD + (PTDPTDI * PDESIZE) 80 81/* Sysmap is the base address of the kernel page tables */ 82 .set _Sysmap,_PTmap + (KPTDI * NBPG) 83 84/* 85 * APTmap, APTD is the alternate recursive pagemap. 86 * It's used when modifying another process's page tables. 87 */ 88 .globl _APTmap,_APTD,_APTDpde 89 .set _APTmap,APTDPTDI << PDRSHIFT 90 .set _APTD,_APTmap + (APTDPTDI * NBPG) 91 .set _APTDpde,_PTD + (APTDPTDI * PDESIZE) 92 93/* 94 * Access to each processes kernel stack is via a region of 95 * per-process address space (at the beginning), immediatly above 96 * the user process stack. 97 */ 98 .set _kstack,USRSTACK 99 .globl _kstack 100 101/* 102 * Globals 103 */ 104 .data 105 106 .globl tmpstk 107 .space 0x1000 /* space for tmpstk - temporary stack */ 108tmpstk: 109 .long 0 /* for debugging tmpstk stack underflow */ 110 111 .globl _boothowto,_bootdev,_curpcb 112 113 .globl _cpu,_cold,_atdevbase,_cpu_vendor,_cpu_id 114 115 .globl _video_mode_ptr 116 117_cpu: .long 0 /* are we 386, 386sx, or 486 */ 118_cpu_id: .long 0 /* stepping ID */ 119_cpu_vendor: .space 20 /* CPU origin code */ 120_video_mode_ptr: .long 0 121_cold: .long 1 /* cold till we are not */ 122_atdevbase: .long 0 /* location of start of iomem in virtual */ 123_atdevphys: .long 0 /* location of device mapping ptes (phys) */ 124 125 .globl _KERNend 126_KERNend: .long 0 /* phys addr end of kernel (just after bss) */ 127 128 .globl _IdlePTD,_KPTphys 129_IdlePTD: .long 0 /* phys addr of kernel PTD */ 130_KPTphys: .long 0 /* phys addr of kernel page tables */ 131 132 .globl _proc0paddr 133_proc0paddr: .long 0 /* address of proc 0 address space */ 134 135#ifdef BDE_DEBUGGER 136 .globl _bdb_exists /* flag to indicate BDE debugger is available */ 137_bdb_exists: .long 0 138#endif 139#if NAPM > 0 140 .globl _apm_current_gdt_pdesc /* current GDT pseudo desc. */ 141_apm_current_gdt_pdesc: 142 .word 0, 0, 0 143 144 .globl _bootstrap_gdt 145_bootstrap_gdt: 146 .space SIZEOF_GDT * BOOTSTRAP_GDT_NUM 147#endif /* NAPM */ 148 149/* 150 * System Initialization 151 */ 152 .text 153 154/* 155 * btext: beginning of text section. 156 * Also the entry point (jumped to directly from the boot blocks). 157 */ 158NON_GPROF_ENTRY(btext) 159 movw $0x1234,0x472 /* warm boot */ 160 jmp 1f 161 /* 162 * XXX now that we load at 1MB is this still really used? 163 */ 164 .org 0x500 /* space for BIOS variables */ 165 1661: 167 /* Set up a real frame, some day we will be doing returns */ 168 pushl %ebp 169 movl %esp, %ebp 170 171 /* Don't trust what the BIOS gives for eflags. */ 172 pushl $PSL_MBO 173 popfl 174 175 /* 176 * This code is called in different ways depending on what loaded 177 * and started the kernel. This is used to detect how we get the 178 * arguments from the other code and what we do with them. 179 * 180 * Old disk boot blocks: 181 * (*btext)(howto, bootdev, cyloffset, esym); 182 * [return address == 0, and can NOT be returned to] 183 * [cyloffset was not supported by the FreeBSD boot code 184 * and always passed in as 0] 185 * [esym is also known as total in the boot code, and 186 * was never properly supported by the FreeBSD boot code] 187 * 188 * Old diskless netboot code: 189 * (*btext)(0,0,0,0,&nfsdiskless,0,0,0); 190 * [return address != 0, and can NOT be returned to] 191 * If we are being booted by this code it will NOT work, 192 * so we are just going to halt if we find this case. 193 * 194 * New uniform boot code: 195 * (*btext)(howto, bootdev, 0, 0, 0, &bootinfo) 196 * [return address != 0, and can be returned to] 197 * 198 * There may seem to be a lot of wasted arguments in here, but 199 * that is so the newer boot code can still load very old kernels 200 * and old boot code can load new kernels. 201 */ 202 203 /* 204 * The old style disk boot blocks fake a frame on the stack and 205 * did an lret to get here. The frame on the stack has a return 206 * address of 0. 207 */ 208 cmpl $0,4(%ebp) 209 je 2f /* olddiskboot: */ 210 211 /* 212 * We have some form of return address, so this is either the 213 * old diskless netboot code, or the new uniform code. That can 214 * be detected by looking at the 5th argument, it if is 0 we 215 * we are being booted by the new unifrom boot code. 216 */ 217 cmpl $0,24(%ebp) 218 je 1f /* newboot: */ 219 220 /* 221 * Seems we have been loaded by the old diskless boot code, we 222 * don't stand a chance of running as the diskless structure 223 * changed considerably between the two, so just halt. 224 */ 225 hlt 226 227 /* 228 * We have been loaded by the new uniform boot code. 229 * Lets check the bootinfo version, and if we do not understand 230 * it we return to the loader with a status of 1 to indicate this error 231 */ 2321: /* newboot: */ 233 movl 28(%ebp),%ebx /* &bootinfo.version */ 234 movl BOOTINFO_VERSION(%ebx),%eax 235 cmpl $1,%eax /* We only understand version 1 */ 236 je 1f 237 movl $1,%eax /* Return status */ 238 leave 239 ret 240 2411: 242 /* 243 * If we have a kernelname copy it in 244 */ 245 movl BOOTINFO_KERNELNAME(%ebx),%esi 246 cmpl $0,%esi 247 je 1f /* No kernelname */ 248 lea _kernelname-KERNBASE,%edi 249 movl $MAXPATHLEN,%ecx /* Brute force!!! */ 250 cld 251 rep 252 movsb 253 2541: 255#ifdef NFS 256 /* 257 * If we have a nfs_diskless structure copy it in 258 */ 259 movl BOOTINFO_NFS_DISKLESS(%ebx),%esi 260 cmpl $0,%esi 261 je 2f 262 lea _nfs_diskless-KERNBASE,%edi 263 movl $NFSDISKLESS_SIZE,%ecx 264 cld 265 rep 266 movsb 267 lea _nfs_diskless_valid-KERNBASE,%edi 268 movl $1,(%edi) 269#endif 270 271 /* 272 * The old style disk boot. 273 * (*btext)(howto, bootdev, cyloffset, esym); 274 * Note that the newer boot code just falls into here to pick 275 * up howto and bootdev, cyloffset and esym are no longer used 276 */ 2772: /* olddiskboot: */ 278 movl 8(%ebp),%eax 279 movl %eax,_boothowto-KERNBASE 280 movl 12(%ebp),%eax 281 movl %eax,_bootdev-KERNBASE 282 283 /* get the BIOS video mode pointer */ 284 movl $0x4a8, %ecx 285 movl (%ecx), %eax 286 movl %eax, %ecx 287 shrl $12, %ecx 288 andl $0xffff0000, %ecx 289 andl $0x0000ffff, %eax 290 orl %ecx, %eax 291 movl (%eax), %eax 292 movl %eax, %ecx 293 shrl $12, %ecx 294 andl $0xffff0000, %ecx 295 andl $0x0000ffff, %eax 296 orl %ecx, %eax 297 addl $KERNBASE, %eax 298 movl %eax, _video_mode_ptr-KERNBASE 299 300#if NAPM > 0 301 /* 302 * Setup APM BIOS: 303 * 304 * APM BIOS initialization should be done from real mode or V86 mode. 305 * 306 * (by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp>) 307 */ 308 309 /* 310 * Copy APM initializer under 1MB boundary: 311 * 312 * APM initializer program must switch the CPU to real mode. 313 * But FreeBSD kernel runs above 1MB boundary. So we must 314 * copy the initializer code to conventional memory. 315 */ 316 movl _apm_init_image_size-KERNBASE, %ecx /* size */ 317 lea _apm_init_image-KERNBASE, %esi /* source */ 318 movl $ APM_OURADDR, %edi /* destination */ 319 cld 320 rep 321 movsb 322 323 /* get GDT base */ 324 sgdt _apm_current_gdt_pdesc-KERNBASE 325 326 /* copy GDT to _bootstrap_gdt */ 327 xorl %ecx, %ecx 328 movw _apm_current_gdt_pdesc-KERNBASE, %cx 329 movl _apm_current_gdt_pdesc-KERNBASE+2, %esi 330 lea _bootstrap_gdt-KERNBASE, %edi 331 cld 332 rep 333 movsb 334 335 /* setup GDT pseudo descriptor */ 336 movw $(SIZEOF_GDT*BOOTSTRAP_GDT_NUM), %ax 337 movw %ax, _apm_current_gdt_pdesc-KERNBASE 338 leal _bootstrap_gdt-KERNBASE, %eax 339 movl %eax, _apm_current_gdt_pdesc-KERNBASE+2 340 341 /* load new GDTR */ 342 lgdt _apm_current_gdt_pdesc-KERNBASE 343 344 /* setup GDT for APM initializer */ 345 lea _bootstrap_gdt-KERNBASE, %ecx 346 movl $(APM_OURADDR), %eax /* use %ax for 15..0 */ 347 movl %eax, %ebx 348 shrl $16, %ebx /* use %bl for 23..16 */ 349 /* use %bh for 31..24 */ 350#define APM_SETUP_GDT(index, attrib) \ 351 movl $(index), %si ; \ 352 lea 0(%ecx,%esi,8), %edx ; \ 353 movw $0xffff, (%edx) ; \ 354 movw %ax, 2(%edx) ; \ 355 movb %bl, 4(%edx) ; \ 356 movw $(attrib), 5(%edx) ; \ 357 movb %bh, 7(%edx) 358 359 APM_SETUP_GDT(APM_INIT_CS_INDEX , CS32_ATTRIB) 360 APM_SETUP_GDT(APM_INIT_DS_INDEX , DS32_ATTRIB) 361 APM_SETUP_GDT(APM_INIT_CS16_INDEX, CS16_ATTRIB) 362 363 /* 364 * Call the initializer: 365 * 366 * direct intersegment call to conventional memory code 367 */ 368 .byte 0x9a /* actually, lcall $APM_INIT_CS_SEL, $0 */ 369 .long 0 370 .word APM_INIT_CS_SEL 371 372 movw %ax, _apm_version-KERNBASE 373 movl %ebx, _apm_cs_entry-KERNBASE 374 movw %cx, _apm_cs32_base-KERNBASE 375 shrl $16, %ecx 376 movw %cx, _apm_cs16_base-KERNBASE 377 movw %dx, _apm_ds_base-KERNBASE 378 movw %si, _apm_cs_limit-KERNBASE 379 shrl $16, %esi 380 movw %si, _apm_ds_limit-KERNBASE 381 movw %di, _apm_flags-KERNBASE 382#endif /* NAPM */ 383 384 /* Find out our CPU type. */ 385 386 /* Try to toggle alignment check flag; does not exist on 386. */ 387 pushfl 388 popl %eax 389 movl %eax,%ecx 390 orl $PSL_AC,%eax 391 pushl %eax 392 popfl 393 pushfl 394 popl %eax 395 xorl %ecx,%eax 396 andl $PSL_AC,%eax 397 pushl %ecx 398 popfl 399 400 testl %eax,%eax 401 jnz 1f 402 movl $CPU_386,_cpu-KERNBASE 403 jmp 2f 404 4051: /* Try to toggle identification flag; does not exist on early 486s. */ 406 pushfl 407 popl %eax 408 movl %eax,%ecx 409 xorl $PSL_ID,%eax 410 pushl %eax 411 popfl 412 pushfl 413 popl %eax 414 xorl %ecx,%eax 415 andl $PSL_ID,%eax 416 pushl %ecx 417 popfl 418 419 testl %eax,%eax 420 jnz 1f 421 movl $CPU_486,_cpu-KERNBASE 422 423 /* check for Cyrix 486DLC -- based on check routine */ 424 /* documented in "Cx486SLC/e SMM Programmer's Guide" */ 425 xorw %dx,%dx 426 cmpw %dx,%dx # set flags to known state 427 pushfw 428 popw %cx # store flags in ecx 429 movw $0xffff,%ax 430 movw $0x0004,%bx 431 divw %bx 432 pushfw 433 popw %ax 434 andw $0x08d5,%ax # mask off important bits 435 andw $0x08d5,%cx 436 cmpw %ax,%cx 437 438 jnz 2f # if flags changed, Intel chip 439 440 movl $CPU_486DLC,_cpu-KERNBASE # set CPU value for Cyrix 441 movl $0x69727943,_cpu_vendor-KERNBASE # store vendor string 442 movw $0x0078,_cpu_vendor-KERNBASE+4 443 444 invd # Start with guaranteed clean cache 445 /* Disable caching of the ISA hole only. */ 446 movb $CCR0,%al # Configuration Register index (CCR0) 447 outb %al,$0x22 448 inb $0x23,%al 449 orb $(CCR0_NC1|CCR0_BARB),%al 450 outb %al,$0x23 451 invd 452 jmp 2f 453 4541: /* Use the `cpuid' instruction. */ 455 xorl %eax,%eax 456 .byte 0x0f,0xa2 # cpuid 0 457 movl %ebx,_cpu_vendor-KERNBASE # store vendor string 458 movl %edx,_cpu_vendor+4-KERNBASE 459 movl %ecx,_cpu_vendor+8-KERNBASE 460 movb $0,_cpu_vendor+12-KERNBASE 461 462 movl $1,%eax 463 .byte 0x0f,0xa2 # cpuid 1 464 movl %eax,_cpu_id-KERNBASE # store cpu_id 465 rorl $8,%eax # extract family type 466 andl $15,%eax 467 cmpl $5,%eax 468 jae 1f 469 470 /* less than Pentium; must be 486 */ 471 movl $CPU_486,_cpu-KERNBASE 472 jmp 2f 473 4741: movl $CPU_586,_cpu-KERNBASE 4752: 476 477 /* 478 * Finished with old stack; load new %esp now instead of later so 479 * we can trace this code without having to worry about the trace 480 * trap clobbering the memory test or the zeroing of the bss+bootstrap 481 * page tables. 482 * 483 * XXX - wdboot clears the bss after testing that this is safe. 484 * This is too wasteful - memory below 640K is scarce. The boot 485 * program should check: 486 * text+data <= &stack_variable - more_space_for_stack 487 * text+data+bss+pad+space_for_page_tables <= end_of_memory 488 * Oops, the gdt is in the carcass of the boot program so clearing 489 * the rest of memory is still not possible. 490 */ 491 movl $tmpstk-KERNBASE,%esp /* bootstrap stack end location */ 492 493/* 494 * Virtual address space of kernel: 495 * 496 * text | data | bss | [syms] | page dir | proc0 kernel stack | usr stk map | Sysmap 497 * pages: 1 UPAGES (2) 1 NKPT (7) 498 */ 499 500/* find end of kernel image */ 501 movl $_end-KERNBASE,%ecx 502 addl $NBPG-1,%ecx /* page align up */ 503 andl $~(NBPG-1),%ecx 504 movl %ecx,%esi /* esi = start of free memory */ 505 movl %ecx,_KERNend-KERNBASE /* save end of kernel */ 506 507/* clear bss */ 508 movl $_edata-KERNBASE,%edi 509 subl %edi,%ecx /* get amount to clear */ 510 xorl %eax,%eax /* specify zero fill */ 511 cld 512 rep 513 stosb 514 515/* 516 * The value in esi is both the end of the kernel bss and a pointer to 517 * the kernel page directory, and is used by the rest of locore to build 518 * the tables. 519 * esi + 1(page dir) + 2(UPAGES) + 1(p0stack) + NKPT(number of kernel 520 * page table pages) is then passed on the stack to init386(first) as 521 * the value first. esi should ALWAYS be page aligned!! 522 */ 523 movl %esi,%ecx /* Get current first availiable address */ 524 525/* clear pagetables, page directory, stack, etc... */ 526 movl %esi,%edi /* base (page directory) */ 527 movl $((1+UPAGES+1+NKPT)*NBPG),%ecx /* amount to clear */ 528 xorl %eax,%eax /* specify zero fill */ 529 cld 530 rep 531 stosb 532 533/* physical address of Idle proc/kernel page directory */ 534 movl %esi,_IdlePTD-KERNBASE 535 536/* 537 * fillkpt 538 * eax = (page frame address | control | status) == pte 539 * ebx = address of page table 540 * ecx = how many pages to map 541 */ 542#define fillkpt \ 5431: movl %eax,(%ebx) ; \ 544 addl $NBPG,%eax ; /* increment physical address */ \ 545 addl $4,%ebx ; /* next pte */ \ 546 loop 1b ; 547 548/* 549 * Map Kernel 550 * 551 * First step - build page tables 552 */ 553#if defined (KGDB) || defined (BDE_DEBUGGER) 554 movl _KERNend-KERNBASE,%ecx /* this much memory, */ 555 shrl $PGSHIFT,%ecx /* for this many PTEs */ 556#ifdef BDE_DEBUGGER 557 cmpl $0xa0,%ecx /* XXX - cover debugger pages */ 558 jae 1f 559 movl $0xa0,%ecx 5601: 561#endif /* BDE_DEBUGGER */ 562 movl $PG_V|PG_KW,%eax /* kernel R/W, valid */ 563 lea ((1+UPAGES+1)*NBPG)(%esi),%ebx /* phys addr of kernel PT base */ 564 movl %ebx,_KPTphys-KERNBASE /* save in global */ 565 fillkpt 566 567#else /* !KGDB && !BDE_DEBUGGER */ 568 /* write protect kernel text (doesn't do a thing for 386's - only 486's) */ 569 movl $_etext-KERNBASE,%ecx /* get size of text */ 570 addl $NBPG-1,%ecx /* round up to page */ 571 shrl $PGSHIFT,%ecx /* for this many PTEs */ 572 movl $PG_V|PG_KR,%eax /* specify read only */ 573#if 0 574 movl $_etext,%ecx /* get size of text */ 575 subl $_btext,%ecx 576 addl $NBPG-1,%ecx /* round up to page */ 577 shrl $PGSHIFT,%ecx /* for this many PTEs */ 578 movl $_btext-KERNBASE,%eax /* get offset to physical memory */ 579 orl $PG_V|PG_KR,%eax /* specify read only */ 580#endif 581 lea ((1+UPAGES+1)*NBPG)(%esi),%ebx /* phys addr of kernel PT base */ 582 movl %ebx,_KPTphys-KERNBASE /* save in global */ 583 fillkpt 584 585 /* data and bss are r/w */ 586 andl $PG_FRAME,%eax /* strip to just addr of bss */ 587 movl _KERNend-KERNBASE,%ecx /* calculate size */ 588 subl %eax,%ecx 589 shrl $PGSHIFT,%ecx 590 orl $PG_V|PG_KW,%eax /* valid, kernel read/write */ 591 fillkpt 592#endif /* KGDB || BDE_DEBUGGER */ 593 594/* now initialize the page dir, upages, p0stack PT, and page tables */ 595 596 movl $(1+UPAGES+1+NKPT),%ecx /* number of PTEs */ 597 movl %esi,%eax /* phys address of PTD */ 598 andl $PG_FRAME,%eax /* convert to PFN, should be a NOP */ 599 orl $PG_V|PG_KW,%eax /* valid, kernel read/write */ 600 movl %esi,%ebx /* calculate pte offset to ptd */ 601 shrl $PGSHIFT-2,%ebx 602 addl %esi,%ebx /* address of page directory */ 603 addl $((1+UPAGES+1)*NBPG),%ebx /* offset to kernel page tables */ 604 fillkpt 605 606/* map I/O memory map */ 607 608 movl _KPTphys-KERNBASE,%ebx /* base of kernel page tables */ 609 lea (0xa0 * PTESIZE)(%ebx),%ebx /* hardwire ISA hole at KERNBASE + 0xa0000 */ 610 movl $0x100-0xa0,%ecx /* for this many pte s, */ 611 movl $(0xa0000|PG_V|PG_KW|PG_N),%eax /* valid, kernel read/write, non-cacheable */ 612 movl %ebx,_atdevphys-KERNBASE /* save phys addr of ptes */ 613 fillkpt 614 615 /* map proc 0's kernel stack into user page table page */ 616 617 movl $UPAGES,%ecx /* for this many pte s, */ 618 lea (1*NBPG)(%esi),%eax /* physical address in proc 0 */ 619 lea (KERNBASE)(%eax),%edx /* change into virtual addr */ 620 movl %edx,_proc0paddr-KERNBASE /* save VA for proc 0 init */ 621 orl $PG_V|PG_KW,%eax /* valid, kernel read/write */ 622 lea ((1+UPAGES)*NBPG)(%esi),%ebx /* addr of stack page table in proc 0 */ 623 addl $(KSTKPTEOFF * PTESIZE),%ebx /* offset to kernel stack PTE */ 624 fillkpt 625 626/* 627 * Initialize kernel page table directory 628 */ 629 /* install a pde for temporary double map of bottom of VA */ 630 movl _KPTphys-KERNBASE,%eax 631 orl $PG_V|PG_KW,%eax /* valid, kernel read/write */ 632 movl %eax,(%esi) /* which is where temp maps! */ 633 634 /* initialize kernel pde's */ 635 movl $(NKPT),%ecx /* for this many PDEs */ 636 lea (KPTDI*PDESIZE)(%esi),%ebx /* offset of pde for kernel */ 637 fillkpt 638 639 /* install a pde recursively mapping page directory as a page table! */ 640 movl %esi,%eax /* phys address of ptd in proc 0 */ 641 orl $PG_V|PG_KW,%eax /* pde entry is valid */ 642 movl %eax,PTDPTDI*PDESIZE(%esi) /* which is where PTmap maps! */ 643 644 /* install a pde to map kernel stack for proc 0 */ 645 lea ((1+UPAGES)*NBPG)(%esi),%eax /* physical address of pt in proc 0 */ 646 orl $PG_V|PG_KW,%eax /* pde entry is valid */ 647 movl %eax,KSTKPTDI*PDESIZE(%esi) /* which is where kernel stack maps! */ 648 649#ifdef BDE_DEBUGGER 650 /* copy and convert stuff from old gdt and idt for debugger */ 651 652 cmpl $0x0375c339,0x96104 /* XXX - debugger signature */ 653 jne 1f 654 movb $1,_bdb_exists-KERNBASE 6551: 656 pushal 657 subl $2*6,%esp 658 659 sgdt (%esp) 660 movl 2(%esp),%esi /* base address of current gdt */ 661 movl $_gdt-KERNBASE,%edi 662 movl %edi,2(%esp) 663 movl $8*18/4,%ecx 664 cld 665 rep /* copy gdt */ 666 movsl 667 movl $_gdt-KERNBASE,-8+2(%edi) /* adjust gdt self-ptr */ 668 movb $0x92,-8+5(%edi) 669 670 sidt 6(%esp) 671 movl 6+2(%esp),%esi /* base address of current idt */ 672 movl 8+4(%esi),%eax /* convert dbg descriptor to ... */ 673 movw 8(%esi),%ax 674 movl %eax,bdb_dbg_ljmp+1-KERNBASE /* ... immediate offset ... */ 675 movl 8+2(%esi),%eax 676 movw %ax,bdb_dbg_ljmp+5-KERNBASE /* ... and selector for ljmp */ 677 movl 24+4(%esi),%eax /* same for bpt descriptor */ 678 movw 24(%esi),%ax 679 movl %eax,bdb_bpt_ljmp+1-KERNBASE 680 movl 24+2(%esi),%eax 681 movw %ax,bdb_bpt_ljmp+5-KERNBASE 682 683 movl $_idt-KERNBASE,%edi 684 movl %edi,6+2(%esp) 685 movl $8*4/4,%ecx 686 cld 687 rep /* copy idt */ 688 movsl 689 690 lgdt (%esp) 691 lidt 6(%esp) 692 693 addl $2*6,%esp 694 popal 695#endif /* BDE_DEBUGGER */ 696 697 /* load base of page directory and enable mapping */ 698 movl %esi,%eax /* phys address of ptd in proc 0 */ 699 movl %eax,%cr3 /* load ptd addr into mmu */ 700 movl %cr0,%eax /* get control word */ 701 orl $CR0_PE|CR0_PG,%eax /* enable paging */ 702 movl %eax,%cr0 /* and let's page NOW! */ 703 704 pushl $begin /* jump to high mem */ 705 ret 706 707begin: /* now running relocated at KERNBASE where the system is linked to run */ 708 movl _atdevphys,%edx /* get pte PA */ 709 subl _KPTphys,%edx /* remove base of ptes, now have phys offset */ 710 shll $PGSHIFT-2,%edx /* corresponding to virt offset */ 711 addl $KERNBASE,%edx /* add virtual base */ 712 movl %edx,_atdevbase 713 714#if N_SC > 0 715 /* XXX: can't scinit relocate Crtat relative to atdevbase itself? */ 716 .globl _Crtat /* XXX - locore should not know about */ 717 movl _Crtat,%eax /* variables of device drivers (pccons)! */ 718 subl $(KERNBASE+0xA0000),%eax 719 addl %eax,%edx 720 movl %edx,_Crtat 721#endif 722 723 /* set up bootstrap stack - 48 bytes */ 724 movl $_kstack+UPAGES*NBPG-4*12,%esp /* bootstrap stack end location */ 725 xorl %eax,%eax /* mark end of frames */ 726 movl %eax,%ebp 727 movl _proc0paddr,%eax 728 movl %esi,PCB_CR3(%eax) 729 730#ifdef BDE_DEBUGGER 731 /* relocate debugger gdt entries */ 732 733 movl $_gdt+8*9,%eax /* adjust slots 9-17 */ 734 movl $9,%ecx 735reloc_gdt: 736 movb $KERNBASE>>24,7(%eax) /* top byte of base addresses, was 0, */ 737 addl $8,%eax /* now KERNBASE>>24 */ 738 loop reloc_gdt 739 740 cmpl $0,_bdb_exists 741 je 1f 742 int $3 7431: 744#endif /* BDE_DEBUGGER */ 745 746 /* 747 * Skip over the page tables and the kernel stack 748 */ 749 lea ((1+UPAGES+1+NKPT)*NBPG)(%esi),%esi 750 751 pushl %esi /* value of first for init386(first) */ 752 call _init386 /* wire 386 chip for unix operation */ 753 popl %esi 754 755 .globl __ucodesel,__udatasel 756 757 pushl $0 /* unused */ 758 pushl __udatasel /* ss */ 759 pushl $0 /* esp - filled in by execve() */ 760 pushl $PSL_USERSET /* eflags (ring 0, int enab) */ 761 pushl __ucodesel /* cs */ 762 pushl $0 /* eip - filled in by execve() */ 763 subl $(12*4),%esp /* space for rest of registers */ 764 765 pushl %esp /* call main with frame pointer */ 766 call _main /* autoconfiguration, mountroot etc */ 767 768 addl $(13*4),%esp /* back to a frame we can return with */ 769 770 /* 771 * now we've run main() and determined what cpu-type we are, we can 772 * enable WP mode on i486 cpus and above. 773 */ 774#if defined(I486_CPU) || defined(I586_CPU) 775 cmpl $CPUCLASS_386,_cpu_class 776 je 1f 777 movl %cr0,%eax /* get control word */ 778 orl $CR0_WP,%eax /* enable write protect for all modes */ 779 movl %eax,%cr0 /* and do it */ 780#endif 781 /* 782 * on return from main(), we are process 1 783 * set up address space and stack so that we can 'return' to user mode 784 */ 7851: 786 movl __ucodesel,%eax 787 movl __udatasel,%ecx 788 789 movl %cx,%ds 790 movl %cx,%es 791 movl %ax,%fs /* double map cs to fs */ 792 movl %cx,%gs /* and ds to gs */ 793 iret /* goto user! */ 794 795#define LCALL(x,y) .byte 0x9a ; .long y ; .word x 796 797NON_GPROF_ENTRY(sigcode) 798 call SIGF_HANDLER(%esp) 799 lea SIGF_SC(%esp),%eax /* scp (the call may have clobbered the */ 800 /* copy at 8(%esp)) */ 801 pushl %eax 802 pushl %eax /* junk to fake return address */ 803 movl $103,%eax /* XXX sigreturn() */ 804 LCALL(0x7,0) /* enter kernel with args on stack */ 805 hlt /* never gets here */ 806 807 .globl _szsigcode 808_szsigcode: 809 .long _szsigcode-_sigcode 810