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