locore.s revision 118154
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
3750477Speter * $FreeBSD: head/sys/i386/i386/locore.s 118154 2003-07-29 11:44:31Z bde $
3815392Sphk *
39757Sdg *		originally from: locore.s, by William F. Jolitz
40757Sdg *
41757Sdg *		Substantially rewritten by David Greenman, Rod Grimes,
4215392Sphk *			Bruce Evans, Wolfgang Solfrank, Poul-Henning Kamp
4315392Sphk *			and many others.
444Srgrimes */
454Srgrimes
4632358Seivind#include "opt_bootp.h"
4790132Sbde#include "opt_compat.h"
4837272Sjmg#include "opt_nfsroot.h"
4914835Sbde
5014835Sbde#include <sys/syscall.h>
515908Sbde#include <sys/reboot.h>
524Srgrimes
5314835Sbde#include <machine/asmacros.h>
5414835Sbde#include <machine/cputypes.h>
5514835Sbde#include <machine/psl.h>
5615543Sphk#include <machine/pmap.h>
5714835Sbde#include <machine/specialreg.h>
5814835Sbde
5914835Sbde#include "assym.s"
6014835Sbde
614Srgrimes/*
62757Sdg *	XXX
63757Sdg *
644Srgrimes * Note: This version greatly munged to avoid various assembler errors
654Srgrimes * that may be fixed in newer versions of gas. Perhaps newer versions
664Srgrimes * will have more pleasant appearance.
674Srgrimes */
684Srgrimes
69200Sdg/*
704Srgrimes * PTmap is recursive pagemap at top of virtual address space.
714Srgrimes * Within PTmap, the page directory can be found (third indirection).
724Srgrimes */
7373011Sjake	.globl	PTmap,PTD,PTDpde
7473011Sjake	.set	PTmap,(PTDPTDI << PDRSHIFT)
7573011Sjake	.set	PTD,PTmap + (PTDPTDI * PAGE_SIZE)
7673011Sjake	.set	PTDpde,PTD + (PTDPTDI * PDESIZE)
77592Srgrimes
7870928Sjake#ifdef SMP
794Srgrimes/*
8070928Sjake * Define layout of per-cpu address space.
8170928Sjake * This is "constructed" in locore.s on the BSP and in mp_machdep.c
8270928Sjake * for each AP.  DO NOT REORDER THESE WITHOUT UPDATING THE REST!
8370928Sjake */
8473011Sjake	.globl	SMP_prvspace, lapic
8573011Sjake	.set	SMP_prvspace,(MPPTDI << PDRSHIFT)
8673011Sjake	.set	lapic,SMP_prvspace + (NPTEPG-1) * PAGE_SIZE
8770928Sjake#endif /* SMP */
8870928Sjake
8970928Sjake/*
9082262Speter * Compiled KERNBASE location
9182262Speter */
9282262Speter	.globl	kernbase
9382262Speter	.set	kernbase,KERNBASE
9482262Speter
9582262Speter/*
96556Srgrimes * Globals
97556Srgrimes */
98556Srgrimes	.data
9999741Sobrien	ALIGN_DATA			/* just to be sure */
100134Sdg
10199741Sobrien	.space	0x2000			/* space for tmpstk - temporary stack */
102118154Sbdetmpstk:
1033842Sdg
10482957Speter	.globl	bootinfo
10599741Sobrienbootinfo:	.space	BOOTINFO_SIZE	/* bootinfo that we can handle */
1064Srgrimes
10799862Speter		.globl KERNend
10899741SobrienKERNend:	.long	0		/* phys addr end of kernel (just after bss) */
10999741Sobrienphysfree:	.long	0		/* phys addr of next free page */
110757Sdg
11126812Speter#ifdef SMP
11273011Sjake		.globl	cpu0prvpage
11399741Sobriencpu0pp:		.long	0		/* phys addr cpu0 private pg */
11499741Sobriencpu0prvpage:	.long	0		/* relocated version */
11525164Speter
11673011Sjake		.globl	SMPpt
11799741SobrienSMPptpa:	.long	0		/* phys addr SMP page table */
11899741SobrienSMPpt:		.long	0		/* relocated version */
11926812Speter#endif /* SMP */
12025164Speter
12173011Sjake	.globl	IdlePTD
12299741SobrienIdlePTD:	.long	0		/* phys addr of kernel PTD */
1233861Sbde
124112841Sjake#ifdef PAE
125112841Sjake	.globl	IdlePDPT
126112841SjakeIdlePDPT:	.long	0		/* phys addr of kernel PDPT */
127112841Sjake#endif
128112841Sjake
12926812Speter#ifdef SMP
13073011Sjake	.globl	KPTphys
13126812Speter#endif
13299741SobrienKPTphys:	.long	0		/* phys addr of kernel page tables */
1334Srgrimes
13483366Sjulian	.globl	proc0uarea, proc0kstack
13599741Sobrienproc0uarea:	.long	0		/* address of proc 0 uarea space */
13699741Sobrienproc0kstack:	.long	0		/* address of proc 0 kstack space */
13799741Sobrienp0upa:		.long	0		/* phys addr of proc0's UAREA */
13899741Sobrienp0kpa:		.long	0		/* phys addr of proc0's STACK */
139134Sdg
14099741Sobrienvm86phystk:	.long	0		/* PA of vm86/bios stack */
14137889Sjlemon
14273011Sjake	.globl	vm86paddr, vm86pa
14399741Sobrienvm86paddr:	.long	0		/* address of vm86 region */
14499741Sobrienvm86pa:		.long	0		/* phys addr of vm86 region */
14534840Sjlemon
14643434Skato#ifdef PC98
14773011Sjake	.globl	pc98_system_parameter
14873011Sjakepc98_system_parameter:
14943434Skato	.space	0x240
15043434Skato#endif
15115428Sphk
15215392Sphk/**********************************************************************
15315392Sphk *
15415392Sphk * Some handy macros
15515392Sphk *
156556Srgrimes */
157134Sdg
15815392Sphk#define R(foo) ((foo)-KERNBASE)
15915392Sphk
16015392Sphk#define ALLOCPAGES(foo) \
16115392Sphk	movl	R(physfree), %esi ; \
16215543Sphk	movl	$((foo)*PAGE_SIZE), %eax ; \
16315392Sphk	addl	%esi, %eax ; \
16415392Sphk	movl	%eax, R(physfree) ; \
16515392Sphk	movl	%esi, %edi ; \
16615543Sphk	movl	$((foo)*PAGE_SIZE),%ecx ; \
16715392Sphk	xorl	%eax,%eax ; \
16815428Sphk	cld ; \
16915428Sphk	rep ; \
17015428Sphk	stosb
17115392Sphk
172134Sdg/*
17315392Sphk * fillkpt
17415565Sphk *	eax = page frame address
17515565Sphk *	ebx = index into page table
17615392Sphk *	ecx = how many pages to map
17715565Sphk * 	base = base address of page dir/table
17815565Sphk *	prot = protection bits
179134Sdg */
18015565Sphk#define	fillkpt(base, prot)		  \
181111299Sjake	shll	$PTESHIFT,%ebx		; \
18219621Sdyson	addl	base,%ebx		; \
18319621Sdyson	orl	$PG_V,%eax		; \
18419621Sdyson	orl	prot,%eax		; \
18515565Sphk1:	movl	%eax,(%ebx)		; \
18615565Sphk	addl	$PAGE_SIZE,%eax		; /* increment physical address */ \
187111299Sjake	addl	$PTESIZE,%ebx		; /* next pte */ \
18815428Sphk	loop	1b
18915392Sphk
19015565Sphk/*
19115565Sphk * fillkptphys(prot)
19215565Sphk *	eax = physical address
19315565Sphk *	ecx = how many pages to map
19415565Sphk *	prot = protection bits
19515565Sphk */
19615565Sphk#define	fillkptphys(prot)		  \
19715565Sphk	movl	%eax, %ebx		; \
19815565Sphk	shrl	$PAGE_SHIFT, %ebx	; \
19973011Sjake	fillkpt(R(KPTphys), prot)
20015565Sphk
20115392Sphk	.text
20215392Sphk/**********************************************************************
20315392Sphk *
20415392Sphk * This is where the bootblocks start us, set the ball rolling...
20515392Sphk *
20615392Sphk */
2071321SdgNON_GPROF_ENTRY(btext)
2084Srgrimes
20924112Skato#ifdef PC98
21024112Skato	/* save SYSTEM PARAMETER for resume (NS/T or other) */
21143434Skato	movl	$0xa1400,%esi
21273011Sjake	movl	$R(pc98_system_parameter),%edi
21343434Skato	movl	$0x0240,%ecx
21424112Skato	cld
21524112Skato	rep
21624112Skato	movsb
21724112Skato#else	/* IBM-PC */
21815392Sphk/* Tell the bios to warmboot next time */
21915392Sphk	movw	$0x1234,0x472
22054128Skato#endif	/* PC98 */
22115392Sphk
22215428Sphk/* Set up a real frame in case the double return in newboot is executed. */
2233384Srgrimes	pushl	%ebp
2243384Srgrimes	movl	%esp, %ebp
2253384Srgrimes
22615392Sphk/* Don't trust what the BIOS gives for eflags. */
2275603Sbde	pushl	$PSL_KERNEL
2282486Sdg	popfl
22915428Sphk
23015428Sphk/*
23115428Sphk * Don't trust what the BIOS gives for %fs and %gs.  Trust the bootstrap
23215428Sphk * to set %cs, %ds, %es and %ss.
23315428Sphk */
23415428Sphk	mov	%ds, %ax
2354217Sphk	mov	%ax, %fs
2364217Sphk	mov	%ax, %gs
2374217Sphk
23815392Sphk	call	recover_bootinfo
23915392Sphk
24015428Sphk/* Get onto a stack that we can trust. */
24115428Sphk/*
24215428Sphk * XXX this step is delayed in case recover_bootinfo needs to return via
24315428Sphk * the old stack, but it need not be, since recover_bootinfo actually
24415428Sphk * returns via the old frame.
24515428Sphk */
246118154Sbde	movl	$R(tmpstk),%esp
24715392Sphk
24824112Skato#ifdef PC98
24943447Skato	/* pc98_machine_type & M_EPSON_PC98 */
25073011Sjake	testb	$0x02,R(pc98_system_parameter)+220
25124112Skato	jz	3f
25243447Skato	/* epson_machine_id <= 0x0b */
25373011Sjake	cmpb	$0x0b,R(pc98_system_parameter)+224
25424112Skato	ja	3f
25524112Skato
25624112Skato	/* count up memory */
25724112Skato	movl	$0x100000,%eax		/* next, talley remaining memory */
25824112Skato	movl	$0xFFF-0x100,%ecx
25924112Skato1:	movl	0(%eax),%ebx		/* save location to check */
26024112Skato	movl	$0xa55a5aa5,0(%eax)	/* write test pattern */
26124112Skato	cmpl	$0xa55a5aa5,0(%eax)	/* does not check yet for rollover */
26224112Skato	jne	2f
26324112Skato	movl	%ebx,0(%eax)		/* restore memory */
26424112Skato	addl	$PAGE_SIZE,%eax
26524112Skato	loop	1b
26624112Skato2:	subl	$0x100000,%eax
26724112Skato	shrl	$17,%eax
26873011Sjake	movb	%al,R(pc98_system_parameter)+1
26924112Skato3:
27058786Skato
27173011Sjake	movw	R(pc98_system_parameter+0x86),%ax
27273011Sjake	movw	%ax,R(cpu_id)
27324112Skato#endif
27424112Skato
27515392Sphk	call	identify_cpu
27615392Sphk
27715428Sphk/*
278117459Speter * We used to clear BSS here, but it isn't needed anymore and actually
279117459Speter * causes harm.  gcc now optimizes 'int foo = 0' to be uninitialized in
280117459Speter * the bss.  All the supported loaders already zero the bss.  The a.out
281117459Speter * kgzip case does not, but we do not generate a.out kernels anymore.
282117459Speter * This is trivial to fix anyway, is a bug in kgzip.
28315428Sphk */
28415392Sphk
28515392Sphk	call	create_pagetables
28615392Sphk
28727993Sdyson/*
28827993Sdyson * If the CPU has support for VME, turn it on.
28927993Sdyson */
29073011Sjake	testl	$CPUID_VME, R(cpu_feature)
29127993Sdyson	jz	1f
29227993Sdyson	movl	%cr4, %eax
29327993Sdyson	orl	$CR4_VME, %eax
29427993Sdyson	movl	%eax, %cr4
29527993Sdyson1:
29627993Sdyson
29715392Sphk/* Now enable paging */
298112841Sjake#ifdef PAE
299112841Sjake	movl	R(IdlePDPT), %eax
300112841Sjake	movl	%eax, %cr3
301112841Sjake	movl	%cr4, %eax
302112841Sjake	orl	$CR4_PAE, %eax
303112841Sjake	movl	%eax, %cr4
304112841Sjake#else
30573011Sjake	movl	R(IdlePTD), %eax
30699741Sobrien	movl	%eax,%cr3		/* load ptd addr into mmu */
307112841Sjake#endif
30899741Sobrien	movl	%cr0,%eax		/* get control word */
30999741Sobrien	orl	$CR0_PE|CR0_PG,%eax	/* enable paging */
31099741Sobrien	movl	%eax,%cr0		/* and let's page NOW! */
31115392Sphk
31299741Sobrien	pushl	$begin			/* jump to high virtualized address */
31315392Sphk	ret
31415392Sphk
31515392Sphk/* now running relocated at KERNBASE where the system is linked to run */
31615392Sphkbegin:
31715392Sphk	/* set up bootstrap stack */
31899741Sobrien	movl	proc0kstack,%eax	/* location of in-kernel stack */
31983366Sjulian			/* bootstrap stack end location */
32083366Sjulian	leal	(KSTACK_PAGES*PAGE_SIZE-PCB_SIZE)(%eax),%esp
32165815Sbde
32299741Sobrien	xorl	%ebp,%ebp		/* mark end of frames */
32365815Sbde
324112841Sjake#ifdef PAE
325112841Sjake	movl	IdlePDPT,%esi
326112841Sjake#else
32773011Sjake	movl	IdlePTD,%esi
328112841Sjake#endif
32983366Sjulian	movl	%esi,(KSTACK_PAGES*PAGE_SIZE-PCB_SIZE+PCB_CR3)(%eax)
33015392Sphk
33199741Sobrien	pushl	physfree		/* value of first for init386(first) */
33299741Sobrien	call	init386			/* wire 386 chip for unix operation */
33315392Sphk
33465815Sbde	/*
33565815Sbde	 * Clean up the stack in a way that db_numargs() understands, so
33665815Sbde	 * that backtraces in ddb don't underrun the stack.  Traps for
33765815Sbde	 * inaccessible memory are more fatal than usual this early.
33865815Sbde	 */
33965815Sbde	addl	$4,%esp
34065815Sbde
34199741Sobrien	call	mi_startup		/* autoconfiguration, mountroot etc */
34265815Sbde	/* NOTREACHED */
34399741Sobrien	addl	$0,%esp			/* for db_numargs() again */
34415392Sphk
34524691Speter/*
34615392Sphk * Signal trampoline, copied to top of user stack
34715392Sphk */
34815392SphkNON_GPROF_ENTRY(sigcode)
349107521Sdeischen	calll	*SIGF_HANDLER(%esp)
350107521Sdeischen	leal	SIGF_UC(%esp),%eax	/* get ucontext */
35115392Sphk	pushl	%eax
35252140Sluoqi	testl	$PSL_VM,UC_EFLAGS(%eax)
353107521Sdeischen	jne	1f
35499741Sobrien	movl	UC_GS(%eax),%gs		/* restore %gs */
355107521Sdeischen1:
35652140Sluoqi	movl	$SYS_sigreturn,%eax
35799741Sobrien	pushl	%eax			/* junk to fake return addr. */
35899741Sobrien	int	$0x80			/* enter kernel with args */
359107521Sdeischen					/* on stack */
360107521Sdeischen1:
361107521Sdeischen	jmp	1b
36252140Sluoqi
363105950Speter#ifdef COMPAT_FREEBSD4
364105950Speter	ALIGN_TEXT
365105950Speterfreebsd4_sigcode:
366107521Sdeischen	calll	*SIGF_HANDLER(%esp)
367107521Sdeischen	leal	SIGF_UC4(%esp),%eax	/* get ucontext */
368105950Speter	pushl	%eax
369105950Speter	testl	$PSL_VM,UC4_EFLAGS(%eax)
370107521Sdeischen	jne	1f
371105950Speter	movl	UC4_GS(%eax),%gs	/* restore %gs */
372107521Sdeischen1:
373105950Speter	movl	$344,%eax		/* 4.x SYS_sigreturn */
374105950Speter	pushl	%eax			/* junk to fake return addr. */
375105950Speter	int	$0x80			/* enter kernel with args */
376107521Sdeischen					/* on stack */
377107521Sdeischen1:
378107521Sdeischen	jmp	1b
379105950Speter#endif
380105950Speter
38190132Sbde#ifdef COMPAT_43
38225083Sjdp	ALIGN_TEXT
38373011Sjakeosigcode:
38499741Sobrien	call	*SIGF_HANDLER(%esp)	/* call signal handler */
38599741Sobrien	lea	SIGF_SC(%esp),%eax	/* get sigcontext */
38652140Sluoqi	pushl	%eax
38752140Sluoqi	testl	$PSL_VM,SC_PS(%eax)
38852140Sluoqi	jne	9f
38999741Sobrien	movl	SC_GS(%eax),%gs		/* restore %gs */
39052140Sluoqi9:
391105950Speter	movl	$103,%eax		/* 3.x SYS_sigreturn */
39299741Sobrien	pushl	%eax			/* junk to fake return addr. */
39399741Sobrien	int	$0x80			/* enter kernel with args */
39452140Sluoqi0:	jmp	0b
39590132Sbde#endif /* COMPAT_43 */
39652140Sluoqi
39752140Sluoqi	ALIGN_TEXT
39873011Sjakeesigcode:
39915392Sphk
40015392Sphk	.data
401105950Speter	.globl	szsigcode
40273011Sjakeszsigcode:
40373011Sjake	.long	esigcode-sigcode
404105950Speter#ifdef COMPAT_FREEBSD4
405105950Speter	.globl	szfreebsd4_sigcode
406105950Speterszfreebsd4_sigcode:
407105950Speter	.long	esigcode-freebsd4_sigcode
408105950Speter#endif
40990132Sbde#ifdef COMPAT_43
410105950Speter	.globl	szosigcode
41173011Sjakeszosigcode:
41273011Sjake	.long	esigcode-osigcode
41390132Sbde#endif
41415428Sphk	.text
41515392Sphk
41615392Sphk/**********************************************************************
41715392Sphk *
41815392Sphk * Recover the bootinfo passed to us from the boot program
41915392Sphk *
42015392Sphk */
42115392Sphkrecover_bootinfo:
42215392Sphk	/*
4233284Srgrimes	 * This code is called in different ways depending on what loaded
4243284Srgrimes	 * and started the kernel.  This is used to detect how we get the
4253284Srgrimes	 * arguments from the other code and what we do with them.
4263284Srgrimes	 *
4273284Srgrimes	 * Old disk boot blocks:
4283284Srgrimes	 *	(*btext)(howto, bootdev, cyloffset, esym);
4293284Srgrimes	 *	[return address == 0, and can NOT be returned to]
4303284Srgrimes	 *	[cyloffset was not supported by the FreeBSD boot code
4313284Srgrimes	 *	 and always passed in as 0]
4323284Srgrimes	 *	[esym is also known as total in the boot code, and
4333284Srgrimes	 *	 was never properly supported by the FreeBSD boot code]
4343284Srgrimes	 *
4353284Srgrimes	 * Old diskless netboot code:
4363284Srgrimes	 *	(*btext)(0,0,0,0,&nfsdiskless,0,0,0);
4373284Srgrimes	 *	[return address != 0, and can NOT be returned to]
4383284Srgrimes	 *	If we are being booted by this code it will NOT work,
4393284Srgrimes	 *	so we are just going to halt if we find this case.
4403284Srgrimes	 *
4413284Srgrimes	 * New uniform boot code:
4423284Srgrimes	 *	(*btext)(howto, bootdev, 0, 0, 0, &bootinfo)
4433284Srgrimes	 *	[return address != 0, and can be returned to]
4443284Srgrimes	 *
4453284Srgrimes	 * There may seem to be a lot of wasted arguments in here, but
4463384Srgrimes	 * that is so the newer boot code can still load very old kernels
4473384Srgrimes	 * and old boot code can load new kernels.
4484Srgrimes	 */
4493284Srgrimes
4503284Srgrimes	/*
4513284Srgrimes	 * The old style disk boot blocks fake a frame on the stack and
4523284Srgrimes	 * did an lret to get here.  The frame on the stack has a return
4533284Srgrimes	 * address of 0.
4543284Srgrimes	 */
4553384Srgrimes	cmpl	$0,4(%ebp)
45615392Sphk	je	olddiskboot
4573284Srgrimes
4583284Srgrimes	/*
4593284Srgrimes	 * We have some form of return address, so this is either the
4603284Srgrimes	 * old diskless netboot code, or the new uniform code.  That can
46115428Sphk	 * be detected by looking at the 5th argument, if it is 0
46215428Sphk	 * we are being booted by the new uniform boot code.
4633284Srgrimes	 */
4643384Srgrimes	cmpl	$0,24(%ebp)
46515392Sphk	je	newboot
4663284Srgrimes
4673284Srgrimes	/*
4683284Srgrimes	 * Seems we have been loaded by the old diskless boot code, we
4693284Srgrimes	 * don't stand a chance of running as the diskless structure
4703284Srgrimes	 * changed considerably between the two, so just halt.
4713284Srgrimes	 */
4723284Srgrimes	 hlt
4733284Srgrimes
4743284Srgrimes	/*
4753384Srgrimes	 * We have been loaded by the new uniform boot code.
47615428Sphk	 * Let's check the bootinfo version, and if we do not understand
4773384Srgrimes	 * it we return to the loader with a status of 1 to indicate this error
4783284Srgrimes	 */
47915392Sphknewboot:
4803384Srgrimes	movl	28(%ebp),%ebx		/* &bootinfo.version */
4815908Sbde	movl	BI_VERSION(%ebx),%eax
4823384Srgrimes	cmpl	$1,%eax			/* We only understand version 1 */
4833384Srgrimes	je	1f
4843384Srgrimes	movl	$1,%eax			/* Return status */
4853384Srgrimes	leave
48615428Sphk	/*
48715428Sphk	 * XXX this returns to our caller's caller (as is required) since
48815428Sphk	 * we didn't set up a frame and our caller did.
48915428Sphk	 */
4903384Srgrimes	ret
4913284Srgrimes
4923384Srgrimes1:
4933284Srgrimes	/*
4943384Srgrimes	 * If we have a kernelname copy it in
4953384Srgrimes	 */
4965908Sbde	movl	BI_KERNELNAME(%ebx),%esi
4973384Srgrimes	cmpl	$0,%esi
4989344Sdg	je	2f			/* No kernelname */
4999344Sdg	movl	$MAXPATHLEN,%ecx	/* Brute force!!! */
50073011Sjake	movl	$R(kernelname),%edi
5019344Sdg	cmpb	$'/',(%esi)		/* Make sure it starts with a slash */
5029344Sdg	je	1f
5039344Sdg	movb	$'/',(%edi)
5049344Sdg	incl	%edi
5059344Sdg	decl	%ecx
5069344Sdg1:
5073384Srgrimes	cld
5083384Srgrimes	rep
5093384Srgrimes	movsb
5103384Srgrimes
5119344Sdg2:
51215428Sphk	/*
5135908Sbde	 * Determine the size of the boot loader's copy of the bootinfo
5145908Sbde	 * struct.  This is impossible to do properly because old versions
5155908Sbde	 * of the struct don't contain a size field and there are 2 old
5165908Sbde	 * versions with the same version number.
5174600Sphk	 */
5185908Sbde	movl	$BI_ENDCOMMON,%ecx	/* prepare for sizeless version */
5195908Sbde	testl	$RB_BOOTINFO,8(%ebp)	/* bi_size (and bootinfo) valid? */
5205908Sbde	je	got_bi_size		/* no, sizeless version */
5215908Sbde	movl	BI_SIZE(%ebx),%ecx
5225908Sbdegot_bi_size:
5235908Sbde
52415428Sphk	/*
5255908Sbde	 * Copy the common part of the bootinfo struct
5265908Sbde	 */
5274600Sphk	movl	%ebx,%esi
52873011Sjake	movl	$R(bootinfo),%edi
5295908Sbde	cmpl	$BOOTINFO_SIZE,%ecx
5305908Sbde	jbe	got_common_bi_size
5314600Sphk	movl	$BOOTINFO_SIZE,%ecx
5325908Sbdegot_common_bi_size:
5334600Sphk	cld
5344600Sphk	rep
5354600Sphk	movsb
5364600Sphk
53738063Smsmith#ifdef NFS_ROOT
53825837Stegge#ifndef BOOTP_NFSV3
5393384Srgrimes	/*
5403384Srgrimes	 * If we have a nfs_diskless structure copy it in
5413384Srgrimes	 */
5425908Sbde	movl	BI_NFS_DISKLESS(%ebx),%esi
5433384Srgrimes	cmpl	$0,%esi
54415428Sphk	je	olddiskboot
54573011Sjake	movl	$R(nfs_diskless),%edi
5463384Srgrimes	movl	$NFSDISKLESS_SIZE,%ecx
5473384Srgrimes	cld
5483384Srgrimes	rep
5493384Srgrimes	movsb
55073011Sjake	movl	$R(nfs_diskless_valid),%edi
5513795Sphk	movl	$1,(%edi)
5523406Sdg#endif
55325837Stegge#endif
5543384Srgrimes
5553384Srgrimes	/*
5563284Srgrimes	 * The old style disk boot.
5573284Srgrimes	 *	(*btext)(howto, bootdev, cyloffset, esym);
5583384Srgrimes	 * Note that the newer boot code just falls into here to pick
5593384Srgrimes	 * up howto and bootdev, cyloffset and esym are no longer used
5603284Srgrimes	 */
56115392Sphkolddiskboot:
5623384Srgrimes	movl	8(%ebp),%eax
56373011Sjake	movl	%eax,R(boothowto)
5643384Srgrimes	movl	12(%ebp),%eax
56573011Sjake	movl	%eax,R(bootdev)
5662783Ssos
56715392Sphk	ret
5683258Sdg
5691321Sdg
57015392Sphk/**********************************************************************
57115392Sphk *
57215392Sphk * Identify the CPU and initialize anything special about it
57315392Sphk *
57415392Sphk */
57515392Sphkidentify_cpu:
57615392Sphk
5771998Swollman	/* Try to toggle alignment check flag; does not exist on 386. */
5781998Swollman	pushfl
5791998Swollman	popl	%eax
5801998Swollman	movl	%eax,%ecx
5811998Swollman	orl	$PSL_AC,%eax
5821998Swollman	pushl	%eax
5831998Swollman	popfl
5841998Swollman	pushfl
5851998Swollman	popl	%eax
5861998Swollman	xorl	%ecx,%eax
5871998Swollman	andl	$PSL_AC,%eax
5881998Swollman	pushl	%ecx
5891998Swollman	popfl
5901998Swollman
5911998Swollman	testl	%eax,%eax
59224112Skato	jnz	try486
59324112Skato
59424112Skato	/* NexGen CPU does not have aligment check flag. */
59524112Skato	pushfl
59624112Skato	movl	$0x5555, %eax
59724112Skato	xorl	%edx, %edx
59824112Skato	movl	$2, %ecx
59924112Skato	clc
60024112Skato	divl	%ecx
60124112Skato	jz	trynexgen
60224112Skato	popfl
60373011Sjake	movl	$CPU_386,R(cpu)
60413081Sdg	jmp	3f
6051998Swollman
60624112Skatotrynexgen:
60727424Skato	popfl
60873011Sjake	movl	$CPU_NX586,R(cpu)
60973011Sjake	movl	$0x4778654e,R(cpu_vendor)	# store vendor string
61073011Sjake	movl	$0x72446e65,R(cpu_vendor+4)
61173011Sjake	movl	$0x6e657669,R(cpu_vendor+8)
61273011Sjake	movl	$0,R(cpu_vendor+12)
61324112Skato	jmp	3f
61424112Skato
61524112Skatotry486:	/* Try to toggle identification flag; does not exist on early 486s. */
6161998Swollman	pushfl
6171998Swollman	popl	%eax
6181998Swollman	movl	%eax,%ecx
6191998Swollman	xorl	$PSL_ID,%eax
6201998Swollman	pushl	%eax
6211998Swollman	popfl
6221998Swollman	pushfl
6231998Swollman	popl	%eax
6241998Swollman	xorl	%ecx,%eax
6251998Swollman	andl	$PSL_ID,%eax
6261998Swollman	pushl	%ecx
6271998Swollman	popfl
6281998Swollman
6291998Swollman	testl	%eax,%eax
63024112Skato	jnz	trycpuid
63173011Sjake	movl	$CPU_486,R(cpu)
6322495Spst
63324112Skato	/*
63424112Skato	 * Check Cyrix CPU
63524112Skato	 * Cyrix CPUs do not change the undefined flags following
63624112Skato	 * execution of the divide instruction which divides 5 by 2.
63724112Skato	 *
63824112Skato	 * Note: CPUID is enabled on M2, so it passes another way.
63924112Skato	 */
64024112Skato	pushfl
64124112Skato	movl	$0x5555, %eax
64224112Skato	xorl	%edx, %edx
64324112Skato	movl	$2, %ecx
64424112Skato	clc
64524112Skato	divl	%ecx
64624112Skato	jnc	trycyrix
64724112Skato	popfl
64824112Skato	jmp	3f		/* You may use Intel CPU. */
6492495Spst
65024112Skatotrycyrix:
65124112Skato	popfl
65224112Skato	/*
65324112Skato	 * IBM Bluelighting CPU also doesn't change the undefined flags.
65424112Skato	 * Because IBM doesn't disclose the information for Bluelighting
65524112Skato	 * CPU, we couldn't distinguish it from Cyrix's (including IBM
65624112Skato	 * brand of Cyrix CPUs).
65724112Skato	 */
65873011Sjake	movl	$0x69727943,R(cpu_vendor)	# store vendor string
65973011Sjake	movl	$0x736e4978,R(cpu_vendor+4)
66073011Sjake	movl	$0x64616574,R(cpu_vendor+8)
66113014Sdg	jmp	3f
6621998Swollman
66324112Skatotrycpuid:	/* Use the `cpuid' instruction. */
6641998Swollman	xorl	%eax,%eax
66569006Smarkm	cpuid					# cpuid 0
66673011Sjake	movl	%eax,R(cpu_high)		# highest capability
66773011Sjake	movl	%ebx,R(cpu_vendor)		# store vendor string
66873011Sjake	movl	%edx,R(cpu_vendor+4)
66973011Sjake	movl	%ecx,R(cpu_vendor+8)
67073011Sjake	movb	$0,R(cpu_vendor+12)
6711998Swollman
6721998Swollman	movl	$1,%eax
67369006Smarkm	cpuid					# cpuid 1
67473011Sjake	movl	%eax,R(cpu_id)			# store cpu_id
675109696Sjhb	movl	%ebx,R(cpu_procinfo)		# store cpu_procinfo
67673011Sjake	movl	%edx,R(cpu_feature)		# store cpu_feature
6776308Sphk	rorl	$8,%eax				# extract family type
6781998Swollman	andl	$15,%eax
6791998Swollman	cmpl	$5,%eax
6801998Swollman	jae	1f
6811998Swollman
6821998Swollman	/* less than Pentium; must be 486 */
68373011Sjake	movl	$CPU_486,R(cpu)
68413000Sdg	jmp	3f
68513000Sdg1:
68613000Sdg	/* a Pentium? */
68713000Sdg	cmpl	$5,%eax
68813000Sdg	jne	2f
68973011Sjake	movl	$CPU_586,R(cpu)
69013000Sdg	jmp	3f
691556Srgrimes2:
69213000Sdg	/* Greater than Pentium...call it a Pentium Pro */
69373011Sjake	movl	$CPU_686,R(cpu)
69413000Sdg3:
69515392Sphk	ret
696556Srgrimes
6974Srgrimes
69815392Sphk/**********************************************************************
699570Srgrimes *
70015428Sphk * Create the first page directory and its page tables.
70115392Sphk *
702570Srgrimes */
703570Srgrimes
70415392Sphkcreate_pagetables:
70515392Sphk
70615428Sphk/* Find end of kernel image (rounded up to a page boundary). */
70715392Sphk	movl	$R(_end),%esi
7084Srgrimes
70961422Sbde/* Include symbols, if any. */
71073011Sjake	movl	R(bootinfo+BI_ESYMTAB),%edi
7115908Sbde	testl	%edi,%edi
71215428Sphk	je	over_symalloc
7135908Sbde	movl	%edi,%esi
7145908Sbde	movl	$KERNBASE,%edi
71573011Sjake	addl	%edi,R(bootinfo+BI_SYMTAB)
71673011Sjake	addl	%edi,R(bootinfo+BI_ESYMTAB)
71715428Sphkover_symalloc:
7185908Sbde
71940081Smsmith/* If we are told where the end of the kernel space is, believe it. */
72073011Sjake	movl	R(bootinfo+BI_KERNEND),%edi
72140081Smsmith	testl	%edi,%edi
72240081Smsmith	je	no_kernend
72340081Smsmith	movl	%edi,%esi
72440081Smsmithno_kernend:
72540081Smsmith
72615565Sphk	addl	$PAGE_MASK,%esi
72715565Sphk	andl	$~PAGE_MASK,%esi
72873011Sjake	movl	%esi,R(KERNend)		/* save end of kernel */
72915428Sphk	movl	%esi,R(physfree)	/* next free page is at end of kernel */
730608Srgrimes
73115392Sphk/* Allocate Kernel Page Tables */
73215392Sphk	ALLOCPAGES(NKPT)
73373011Sjake	movl	%esi,R(KPTphys)
734757Sdg
73515392Sphk/* Allocate Page Table Directory */
736112841Sjake#ifdef PAE
737112841Sjake	/* XXX only need 32 bytes (easier for now) */
738112841Sjake	ALLOCPAGES(1)
739112841Sjake	movl	%esi,R(IdlePDPT)
740112841Sjake#endif
741111363Sjake	ALLOCPAGES(NPGPTD)
74273011Sjake	movl	%esi,R(IdlePTD)
7434Srgrimes
74415392Sphk/* Allocate UPAGES */
74583366Sjulian	ALLOCPAGES(UAREA_PAGES)
74617120Sbde	movl	%esi,R(p0upa)
74715392Sphk	addl	$KERNBASE, %esi
74883366Sjulian	movl	%esi, R(proc0uarea)
7494Srgrimes
75083366Sjulian	ALLOCPAGES(KSTACK_PAGES)
75183366Sjulian	movl	%esi,R(p0kpa)
75283366Sjulian	addl	$KERNBASE, %esi
75383366Sjulian	movl	%esi, R(proc0kstack)
75483366Sjulian
75537889Sjlemon	ALLOCPAGES(1)			/* vm86/bios stack */
75637889Sjlemon	movl	%esi,R(vm86phystk)
75737889Sjlemon
75837889Sjlemon	ALLOCPAGES(3)			/* pgtable + ext + IOPAGES */
75973011Sjake	movl	%esi,R(vm86pa)
76034840Sjlemon	addl	$KERNBASE, %esi
76173011Sjake	movl	%esi, R(vm86paddr)
76234840Sjlemon
76326812Speter#ifdef SMP
76425164Speter/* Allocate cpu0's private data page */
76525164Speter	ALLOCPAGES(1)
76625164Speter	movl	%esi,R(cpu0pp)
76725164Speter	addl	$KERNBASE, %esi
76873011Sjake	movl	%esi, R(cpu0prvpage)	/* relocated to KVM space */
76925164Speter
77046129Sluoqi/* Allocate SMP page table page */
77125164Speter	ALLOCPAGES(1)
77246129Sluoqi	movl	%esi,R(SMPptpa)
77325164Speter	addl	$KERNBASE, %esi
77473011Sjake	movl	%esi, R(SMPpt)		/* relocated to KVM space */
77526812Speter#endif	/* SMP */
77625164Speter
77715392Sphk/* Map read-only from zero to the end of the kernel text section */
77815565Sphk	xorl	%eax, %eax
77919621Sdyson	xorl	%edx,%edx
78099862Speter	movl	$R(etext),%ecx
78115565Sphk	addl	$PAGE_MASK,%ecx
78215565Sphk	shrl	$PAGE_SHIFT,%ecx
78319621Sdyson	fillkptphys(%edx)
784757Sdg
78515392Sphk/* Map read-write, data, bss and symbols */
78673011Sjake	movl	$R(etext),%eax
78715694Sphk	addl	$PAGE_MASK, %eax
78815694Sphk	andl	$~PAGE_MASK, %eax
78919621Sdyson	movl	$PG_RW,%edx
79099862Speter	movl	R(KERNend),%ecx
791757Sdg	subl	%eax,%ecx
79215543Sphk	shrl	$PAGE_SHIFT,%ecx
79319621Sdyson	fillkptphys(%edx)
794757Sdg
79515428Sphk/* Map page directory. */
796112841Sjake#ifdef PAE
797112841Sjake	movl	R(IdlePDPT), %eax
798112841Sjake	movl	$1, %ecx
799112841Sjake	fillkptphys($PG_RW)
800112841Sjake#endif
801112841Sjake
80273011Sjake	movl	R(IdlePTD), %eax
803111363Sjake	movl	$NPGPTD, %ecx
80419621Sdyson	fillkptphys($PG_RW)
805757Sdg
80617120Sbde/* Map proc0's UPAGES in the physical way ... */
80717120Sbde	movl	R(p0upa), %eax
80883366Sjulian	movl	$(UAREA_PAGES), %ecx
80919621Sdyson	fillkptphys($PG_RW)
8104Srgrimes
81183366Sjulian/* Map proc0's KSTACK in the physical way ... */
81283366Sjulian	movl	R(p0kpa), %eax
81383366Sjulian	movl	$(KSTACK_PAGES), %ecx
81483366Sjulian	fillkptphys($PG_RW)
81583366Sjulian
81615565Sphk/* Map ISA hole */
81715565Sphk	movl	$ISA_HOLE_START, %eax
81815565Sphk	movl	$ISA_HOLE_LENGTH>>PAGE_SHIFT, %ecx
81922130Sdg	fillkptphys($PG_RW)
82015565Sphk
82134840Sjlemon/* Map space for the vm86 region */
82237889Sjlemon	movl	R(vm86phystk), %eax
82334840Sjlemon	movl	$4, %ecx
82434840Sjlemon	fillkptphys($PG_RW)
82534840Sjlemon
82634840Sjlemon/* Map page 0 into the vm86 page table */
82734840Sjlemon	movl	$0, %eax
82834840Sjlemon	movl	$0, %ebx
82934840Sjlemon	movl	$1, %ecx
83073011Sjake	fillkpt(R(vm86pa), $PG_RW|PG_U)
83134840Sjlemon
83234840Sjlemon/* ...likewise for the ISA hole */
83334840Sjlemon	movl	$ISA_HOLE_START, %eax
83434840Sjlemon	movl	$ISA_HOLE_START>>PAGE_SHIFT, %ebx
83534840Sjlemon	movl	$ISA_HOLE_LENGTH>>PAGE_SHIFT, %ecx
83673011Sjake	fillkpt(R(vm86pa), $PG_RW|PG_U)
83734840Sjlemon
83826812Speter#ifdef SMP
83926812Speter/* Map cpu0's private page into global kmem (4K @ cpu0prvpage) */
84025164Speter	movl	R(cpu0pp), %eax
84125164Speter	movl	$1, %ecx
84225164Speter	fillkptphys($PG_RW)
84325164Speter
84446129Sluoqi/* Map SMP page table page into global kmem FWIW */
84546129Sluoqi	movl	R(SMPptpa), %eax
84625164Speter	movl	$1, %ecx
84725164Speter	fillkptphys($PG_RW)
84825164Speter
84946129Sluoqi/* Map the private page into the SMP page table */
85025164Speter	movl	R(cpu0pp), %eax
85125164Speter	movl	$0, %ebx		/* pte offset = 0 */
85225164Speter	movl	$1, %ecx		/* one private page coming right up */
85346129Sluoqi	fillkpt(R(SMPptpa), $PG_RW)
85425164Speter
85526812Speter/* ... and put the page table table in the pde. */
85646129Sluoqi	movl	R(SMPptpa), %eax
85725164Speter	movl	$MPPTDI, %ebx
85825164Speter	movl	$1, %ecx
85973011Sjake	fillkpt(R(IdlePTD), $PG_RW)
86034840Sjlemon
86134840Sjlemon/* Fakeup VA for the local apic to allow early traps. */
86234840Sjlemon	ALLOCPAGES(1)
86334840Sjlemon	movl	%esi, %eax
86446129Sluoqi	movl	$(NPTEPG-1), %ebx	/* pte offset = NTEPG-1 */
86534840Sjlemon	movl	$1, %ecx		/* one private pt coming right up */
86646129Sluoqi	fillkpt(R(SMPptpa), $PG_RW)
86726812Speter#endif	/* SMP */
86825164Speter
86915392Sphk/* install a pde for temporary double map of bottom of VA */
87073011Sjake	movl	R(KPTphys), %eax
87115565Sphk	xorl	%ebx, %ebx
87274283Speter	movl	$NKPT, %ecx
87373011Sjake	fillkpt(R(IdlePTD), $PG_RW)
8744Srgrimes
87515392Sphk/* install pde's for pt's */
87673011Sjake	movl	R(KPTphys), %eax
87715565Sphk	movl	$KPTDI, %ebx
87815565Sphk	movl	$NKPT, %ecx
87973011Sjake	fillkpt(R(IdlePTD), $PG_RW)
8804Srgrimes
88115392Sphk/* install a pde recursively mapping page directory as a page table */
88273011Sjake	movl	R(IdlePTD), %eax
88315565Sphk	movl	$PTDPTDI, %ebx
884111372Sjake	movl	$NPGPTD,%ecx
88573011Sjake	fillkpt(R(IdlePTD), $PG_RW)
8864Srgrimes
887112841Sjake#ifdef PAE
888112841Sjake	movl	R(IdlePTD), %eax
889112841Sjake	xorl	%ebx, %ebx
890112841Sjake	movl	$NPGPTD, %ecx
891112841Sjake	fillkpt(R(IdlePDPT), $0x0)
892112841Sjake#endif
893112841Sjake
8944Srgrimes	ret
895