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 + -
显示快捷键?