locore.s
来自「基于组件方式开发操作系统的OSKIT源代码」· S 代码 · 共 2,444 行 · 第 1/4 页
S
2,444 行
/* $NetBSD: locore.s,v 1.231 2000/12/11 05:28:59 mycroft Exp $ *//*- * Copyright (c) 1998 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Charles M. Hannum. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. *//*- * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * William Jolitz. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)locore.s 7.3 (Berkeley) 5/13/91 */#include "opt_cputype.h"#include "opt_ddb.h"#include "opt_ipkdb.h"#include "opt_vm86.h"#include "opt_user_ldt.h"#include "opt_dummy_nops.h"#include "opt_compat_oldboot.h"#include "opt_multiprocessor.h"#include "opt_lockdebug.h"#ifndef OSKIT#include "npx.h"#include "assym.h"#include "apm.h"#else#include "oskit_uvm_asm.h"#define PCB_ONFAULT UVM_PCB_ONFAULT#endif #include <sys/errno.h>#include <sys/syscall.h>#include <machine/cputypes.h>#include <machine/param.h>#include <machine/pte.h>#include <machine/segments.h>#include <machine/specialreg.h>#include <machine/trap.h>#include <machine/bootinfo.h>/* * override user-land alignment before including asm.h */#ifdef __ELF__#define ALIGN_DATA .align 4#define ALIGN_TEXT .align 4,0x90 /* 4-byte boundaries, NOP-filled */#define SUPERALIGN_TEXT .align 16,0x90 /* 16-byte boundaries better for 486 */#else#define ALIGN_DATA .align 2#define ALIGN_TEXT .align 2,0x90 /* 4-byte boundaries, NOP-filled */#define SUPERALIGN_TEXT .align 4,0x90 /* 16-byte boundaries better for 486 */#endif#define _ALIGN_TEXT ALIGN_TEXT#include <machine/asm.h>#ifndef OSKIT/* XXX temporary kluge; these should not be here *//* Get definitions for IOM_BEGIN, IOM_END, and IOM_SIZE */#include <dev/isa/isareg.h>#endif/* NB: NOP now preserves registers so NOPs can be inserted anywhere *//* XXX: NOP and FASTER_NOP are misleadingly named */#ifdef DUMMY_NOPS /* this will break some older machines */#define FASTER_NOP#define NOP#else#define FASTER_NOP pushl %eax ; inb $0x84,%al ; popl %eax#define NOP pushl %eax ; inb $0x84,%al ; inb $0x84,%al ; popl %eax#endif/* Disallow old names for REALBASEMEM */#ifdef BIOSBASEMEM#error BIOSBASEMEM option deprecated; use REALBASEMEM only if memory size reported by latest boot block is incorrect#endif/* Disallow old names for REALEXTMEM */#ifdef EXTMEM_SIZE#error EXTMEM_SIZE option deprecated; use REALEXTMEM only if memory size reported by latest boot block is incorrect#endif#ifdef BIOSEXTMEM#error BIOSEXTMEM option deprecated; use REALEXTMEM only if memory size reported by latest boot block is incorrect#endif/* * These are used on interrupt or trap entry or exit. */#define INTRENTRY \ pushl %eax ; \ pushl %ecx ; \ pushl %edx ; \ pushl %ebx ; \ pushl %ebp ; \ pushl %esi ; \ pushl %edi ; \ pushl %ds ; \ pushl %es ; \ movl $GSEL(GDATA_SEL, SEL_KPL),%eax ; \ movl %ax,%ds ; \ movl %ax,%es#define INTRFASTEXIT \ popl %es ; \ popl %ds ; \ popl %edi ; \ popl %esi ; \ popl %ebp ; \ popl %ebx ; \ popl %edx ; \ popl %ecx ; \ popl %eax ; \ addl $8,%esp ; \ iret/* * PTmap is recursive pagemap at top of virtual address space. * Within PTmap, the page directory can be found (third indirection). * * XXX 4 == sizeof pde */ .set _C_LABEL(PTmap),(PDSLOT_PTE << PDSHIFT)#ifndef OSKIT .set _C_LABEL(PTD),(_C_LABEL(PTmap) + PDSLOT_PTE * NBPG) .set _C_LABEL(PTDpde),(_C_LABEL(PTD) + PDSLOT_PTE * 4)/* * APTmap, APTD is the alternate recursive pagemap. * It's used when modifying another process's page tables. * * XXX 4 == sizeof pde */ .set _C_LABEL(APTmap),(PDSLOT_APTE << PDSHIFT) .set _C_LABEL(APTD),(_C_LABEL(APTmap) + PDSLOT_APTE * NBPG) .set _C_LABEL(APTDpde),(_C_LABEL(PTD) + PDSLOT_APTE * 4)/* * Initialization */ .data .globl _C_LABEL(cpu),_C_LABEL(cpu_id),_C_LABEL(cpu_vendor) .globl _C_LABEL(cpuid_level),_C_LABEL(cpu_feature) .globl _C_LABEL(cpu_brand_id) .globl _C_LABEL(esym),_C_LABEL(boothowto) .globl _C_LABEL(bootinfo),_C_LABEL(atdevbase)#ifdef COMPAT_OLDBOOT .globl _C_LABEL(bootdev)#endif .globl _C_LABEL(proc0paddr),_C_LABEL(curpcb),_C_LABEL(PTDpaddr) .globl _C_LABEL(biosbasemem),_C_LABEL(biosextmem) .globl _C_LABEL(gdt)#ifdef I586_CPU .globl _C_LABEL(idt)#endif_C_LABEL(cpu): .long 0 # are we 386, 386sx, or 486, # or Pentium, or.._C_LABEL(cpu_id): .long 0 # saved from `cpuid' instruction_C_LABEL(cpu_feature): .long 0 # feature flags from 'cpuid' # instruction_C_LABEL(cpuid_level): .long -1 # max. level accepted by 'cpuid' # instruction_C_LABEL(cpu_vendor): .space 16 # vendor string returned by `cpuid' # instruction_C_LABEL(cpu_brand_id): .long 0 # brand ID from 'cpuid' instruction_C_LABEL(esym): .long 0 # ptr to end of syms_C_LABEL(atdevbase): .long 0 # location of start of iomem in virtual_C_LABEL(proc0paddr): .long 0_C_LABEL(PTDpaddr): .long 0 # paddr of PTD, for libkvm#ifndef REALBASEMEM_C_LABEL(biosbasemem): .long 0 # base memory reported by BIOS#else_C_LABEL(biosbasemem): .long REALBASEMEM#endif#ifndef REALEXTMEM_C_LABEL(biosextmem): .long 0 # extended memory reported by BIOS#else_C_LABEL(biosextmem): .long REALEXTMEM#endif .space 512tmpstk:#define _RELOC(x) ((x) - KERNBASE)#define RELOC(x) _RELOC(_C_LABEL(x)) .text .globl _C_LABEL(kernel_text) .set _C_LABEL(kernel_text),KERNTEXTOFF .globl startstart: movw $0x1234,0x472 # warm boot /* * Load parameters from stack * (howto, [bootdev], bootinfo, esym, basemem, extmem). */ movl 4(%esp),%eax movl %eax,RELOC(boothowto)#ifdef COMPAT_OLDBOOT movl 8(%esp),%eax movl %eax,RELOC(bootdev)#endif movl 12(%esp),%eax testl %eax, %eax jz 1f movl (%eax), %ebx /* number of entries */ movl $RELOC(bootinfo), %edx movl %ebx, (%edx) addl $4, %edx2: testl %ebx, %ebx jz 1f addl $4, %eax movl (%eax), %ecx /* address of entry */ pushl %eax pushl (%ecx) /* len */ pushl %edx addl (%ecx), %edx /* update dest pointer */ cmpl $_RELOC(_C_LABEL(bootinfo) + BOOTINFO_MAXSIZE), %edx jg 2f pushl %ecx call _C_LABEL(bcopy) addl $12, %esp popl %eax subl $1, %ebx jmp 2b2: /* cleanup for overflow case */ addl $12, %esp movl $RELOC(bootinfo), %edx subl %ebx, (%edx) /* correct number of entries */1: movl 16(%esp),%eax testl %eax,%eax jz 1f addl $KERNBASE,%eax1: movl %eax,RELOC(esym) movl RELOC(biosextmem),%eax testl %eax,%eax jnz 1f movl 20(%esp),%eax movl %eax,RELOC(biosextmem)1: movl RELOC(biosbasemem),%eax testl %eax,%eax jnz 1f movl 24(%esp),%eax movl %eax,RELOC(biosbasemem)1: /* First, reset the PSL. */ pushl $PSL_MBO popfl /* Find out our CPU type. */try386: /* Try to toggle alignment check flag; does not exist on 386. */ pushfl popl %eax movl %eax,%ecx orl $PSL_AC,%eax pushl %eax popfl pushfl popl %eax xorl %ecx,%eax andl $PSL_AC,%eax pushl %ecx popfl testl %eax,%eax jnz try486 /* * Try the test of a NexGen CPU -- ZF will not change on a DIV * instruction on a NexGen, it will on an i386. Documented in * Nx586 Processor Recognition Application Note, NexGen, Inc. */ movl $0x5555,%eax xorl %edx,%edx movl $2,%ecx divl %ecx jnz is386isnx586: /* * Don't try cpuid, as Nx586s reportedly don't support the * PSL_ID bit. */ movl $CPU_NX586,RELOC(cpu) jmp 2fis386: movl $CPU_386,RELOC(cpu) jmp 2ftry486: /* Try to toggle identification flag; does not exist on early 486s. */ pushfl popl %eax movl %eax,%ecx xorl $PSL_ID,%eax pushl %eax popfl pushfl popl %eax xorl %ecx,%eax andl $PSL_ID,%eax pushl %ecx popfl testl %eax,%eax jnz try586is486: movl $CPU_486,RELOC(cpu) /* * Check Cyrix CPU * Cyrix CPUs do not change the undefined flags following * execution of the divide instruction which divides 5 by 2. * * Note: CPUID is enabled on M2, so it passes another way. */ pushfl movl $0x5555, %eax xorl %edx, %edx movl $2, %ecx clc divl %ecx jnc trycyrix486 popfl jmp 2ftrycyrix486: movl $CPU_6x86,RELOC(cpu) # set CPU type /* * Check for Cyrix 486 CPU by seeing if the flags change during a * divide. This is documented in the Cx486SLC/e SMM Programmer's * Guide. */ xorl %edx,%edx cmpl %edx,%edx # set flags to known state pushfl popl %ecx # store flags in ecx movl $-1,%eax movl $4,%ebx divl %ebx # do a long division pushfl popl %eax xorl %ecx,%eax # are the flags different? testl $0x8d5,%eax # only check C|PF|AF|Z|N|V jne 2f # yes; must be Cyrix 6x86 CPU movl $CPU_486DLC,RELOC(cpu) # set CPU type#ifndef CYRIX_CACHE_WORKS /* Disable caching of the ISA hole only. */ invd movb $CCR0,%al # Configuration Register index (CCR0) outb %al,$0x22 inb $0x23,%al orb $(CCR0_NC1|CCR0_BARB),%al movb %al,%ah movb $CCR0,%al outb %al,$0x22 movb %ah,%al outb %al,$0x23 invd#else /* CYRIX_CACHE_WORKS */ /* Set cache parameters */ invd # Start with guaranteed clean cache movb $CCR0,%al # Configuration Register index (CCR0) outb %al,$0x22 inb $0x23,%al andb $~CCR0_NC0,%al#ifndef CYRIX_CACHE_REALLY_WORKS orb $(CCR0_NC1|CCR0_BARB),%al#else orb $CCR0_NC1,%al#endif movb %al,%ah movb $CCR0,%al outb %al,$0x22 movb %ah,%al outb %al,$0x23 /* clear non-cacheable region 1 */ movb $(NCR1+2),%al outb %al,$0x22 movb $NCR_SIZE_0K,%al outb %al,$0x23 /* clear non-cacheable region 2 */ movb $(NCR2+2),%al outb %al,$0x22 movb $NCR_SIZE_0K,%al outb %al,$0x23 /* clear non-cacheable region 3 */ movb $(NCR3+2),%al outb %al,$0x22 movb $NCR_SIZE_0K,%al outb %al,$0x23 /* clear non-cacheable region 4 */ movb $(NCR4+2),%al outb %al,$0x22 movb $NCR_SIZE_0K,%al outb %al,$0x23 /* enable caching in CR0 */ movl %cr0,%eax andl $~(CR0_CD|CR0_NW),%eax movl %eax,%cr0 invd#endif /* CYRIX_CACHE_WORKS */ jmp 2ftry586: /* Use the `cpuid' instruction. */ xorl %eax,%eax cpuid movl %eax,RELOC(cpuid_level) movl %ebx,RELOC(cpu_vendor) # store vendor string movl %edx,RELOC(cpu_vendor)+4 movl %ecx,RELOC(cpu_vendor)+8 movl $0, RELOC(cpu_vendor)+12 movl $1,%eax cpuid movl %eax,RELOC(cpu_id) # store cpu_id and features movl %edx,RELOC(cpu_feature) /* Brand ID is bits 0-7 of %ebx */ andl $255,%ebx movl %ebx,RELOC(cpu_brand_id)2: /* * Finished with old stack; load new %esp now instead of later so we * can trace this code without having to worry about the trace trap * clobbering the memory test or the zeroing of the bss+bootstrap page * tables. * * The boot program should check: * text+data <= &stack_variable - more_space_for_stack * text+data+bss+pad+space_for_page_tables <= end_of_memory * Oops, the gdt is in the carcass of the boot program so clearing * the rest of memory is still not possible. */ movl $_RELOC(tmpstk),%esp # bootstrap stack end location/* * Virtual address space of kernel: * * text | data | bss | [syms] | page dir | proc0 kstack * 0 1 2 3 */#define PROC0PDIR ((0) * NBPG)#define PROC0STACK ((1) * NBPG)#define SYSMAP ((1+UPAGES) * NBPG)#define TABLESIZE ((1+UPAGES) * NBPG) /* + nkpde * NBPG */ /* Find end of kernel image. */ movl $RELOC(end),%edi#if defined(DDB) && !defined(SYMTAB_SPACE) /* Save the symbols (if loaded). */ movl RELOC(esym),%eax testl %eax,%eax jz 1f subl $KERNBASE,%eax movl %eax,%edi1:#endif /* Calculate where to start the bootstrap tables. */ movl %edi,%esi # edi = esym ? esym : end addl $PGOFSET,%esi # page align up andl $~PGOFSET,%esi /* * Calculate the size of the kernel page table directory, and * how many entries it will have. */ movl RELOC(nkpde),%ecx # get nkpde cmpl $NKPTP_MIN,%ecx # larger than min? jge 1f movl $NKPTP_MIN,%ecx # set at min jmp 2f1: cmpl $NKPTP_MAX,%ecx # larger than max? jle 2f movl $NKPTP_MAX,%ecx2: /* Clear memory for bootstrap tables. */ shll $PGSHIFT,%ecx addl $TABLESIZE,%ecx addl %esi,%ecx # end of tables subl %edi,%ecx # size of tables shrl $2,%ecx xorl %eax,%eax cld rep stosl/* * fillkpt * eax = pte (page frame | control | status) * ebx = page table address * ecx = number of pages to map */#define fillkpt \1: movl %eax,(%ebx) ; \ addl $NBPG,%eax ; /* increment physical address */ \ addl $4,%ebx ; /* next pte */ \ loop 1b ;/* * Build initial page tables. */ /* Calculate end of text segment, rounded to a page. */ leal (RELOC(etext)+PGOFSET),%edx andl $~PGOFSET,%edx /* Skip over the first 1MB. */ movl $_RELOC(KERNTEXTOFF),%eax movl %eax,%ecx shrl $PGSHIFT,%ecx leal (SYSMAP)(%esi,%ecx,4),%ebx /* Map the kernel text read-only. */ movl %edx,%ecx subl %eax,%ecx shrl $PGSHIFT,%ecx orl $(PG_V|PG_KR),%eax fillkpt /* Map the data, BSS, and bootstrap tables read-write. */ leal (PG_V|PG_KW)(%edx),%eax movl RELOC(nkpde),%ecx shll $PGSHIFT,%ecx addl $TABLESIZE,%ecx addl %esi,%ecx # end of tables subl %edx,%ecx # subtract end of text shrl $PGSHIFT,%ecx fillkpt /* Map ISA I/O memory. */ movl $(IOM_BEGIN|PG_V|PG_KW/*|PG_N*/),%eax # having these bits set
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?