locore.s revision 120690
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 120690 2003-10-03 14:33:00Z peter $
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"
49120690Speter#include "opt_pmap.h"
5014835Sbde
5114835Sbde#include <sys/syscall.h>
525908Sbde#include <sys/reboot.h>
534Srgrimes
5414835Sbde#include <machine/asmacros.h>
5514835Sbde#include <machine/cputypes.h>
5614835Sbde#include <machine/psl.h>
5715543Sphk#include <machine/pmap.h>
5814835Sbde#include <machine/specialreg.h>
5914835Sbde
6014835Sbde#include "assym.s"
6114835Sbde
624Srgrimes/*
63757Sdg *	XXX
64757Sdg *
654Srgrimes * Note: This version greatly munged to avoid various assembler errors
664Srgrimes * that may be fixed in newer versions of gas. Perhaps newer versions
674Srgrimes * will have more pleasant appearance.
684Srgrimes */
694Srgrimes
70200Sdg/*
714Srgrimes * PTmap is recursive pagemap at top of virtual address space.
724Srgrimes * Within PTmap, the page directory can be found (third indirection).
734Srgrimes */
7473011Sjake	.globl	PTmap,PTD,PTDpde
7573011Sjake	.set	PTmap,(PTDPTDI << PDRSHIFT)
7673011Sjake	.set	PTD,PTmap + (PTDPTDI * PAGE_SIZE)
7773011Sjake	.set	PTDpde,PTD + (PTDPTDI * PDESIZE)
78592Srgrimes
7970928Sjake#ifdef SMP
804Srgrimes/*
8170928Sjake * Define layout of per-cpu address space.
8270928Sjake * This is "constructed" in locore.s on the BSP and in mp_machdep.c
8370928Sjake * for each AP.  DO NOT REORDER THESE WITHOUT UPDATING THE REST!
8470928Sjake */
8573011Sjake	.globl	SMP_prvspace, lapic
8673011Sjake	.set	SMP_prvspace,(MPPTDI << PDRSHIFT)
8773011Sjake	.set	lapic,SMP_prvspace + (NPTEPG-1) * PAGE_SIZE
8870928Sjake#endif /* SMP */
8970928Sjake
9070928Sjake/*
91120654Speter * Compiled KERNBASE location and the kernel load address
9282262Speter */
9382262Speter	.globl	kernbase
9482262Speter	.set	kernbase,KERNBASE
95120654Speter	.globl	kernload
96120654Speter	.set	kernload,KERNLOAD
9782262Speter
9882262Speter/*
99556Srgrimes * Globals
100556Srgrimes */
101556Srgrimes	.data
10299741Sobrien	ALIGN_DATA			/* just to be sure */
103134Sdg
10499741Sobrien	.space	0x2000			/* space for tmpstk - temporary stack */
105118154Sbdetmpstk:
1063842Sdg
10782957Speter	.globl	bootinfo
10899741Sobrienbootinfo:	.space	BOOTINFO_SIZE	/* bootinfo that we can handle */
1094Srgrimes
11099862Speter		.globl KERNend
11199741SobrienKERNend:	.long	0		/* phys addr end of kernel (just after bss) */
11299741Sobrienphysfree:	.long	0		/* phys addr of next free page */
113757Sdg
11426812Speter#ifdef SMP
11573011Sjake		.globl	cpu0prvpage
11699741Sobriencpu0pp:		.long	0		/* phys addr cpu0 private pg */
11799741Sobriencpu0prvpage:	.long	0		/* relocated version */
11825164Speter
11973011Sjake		.globl	SMPpt
12099741SobrienSMPptpa:	.long	0		/* phys addr SMP page table */
12199741SobrienSMPpt:		.long	0		/* relocated version */
12226812Speter#endif /* SMP */
12325164Speter
12473011Sjake	.globl	IdlePTD
12599741SobrienIdlePTD:	.long	0		/* phys addr of kernel PTD */
1263861Sbde
127112841Sjake#ifdef PAE
128112841Sjake	.globl	IdlePDPT
129112841SjakeIdlePDPT:	.long	0		/* phys addr of kernel PDPT */
130112841Sjake#endif
131112841Sjake
13226812Speter#ifdef SMP
13373011Sjake	.globl	KPTphys
13426812Speter#endif
13599741SobrienKPTphys:	.long	0		/* phys addr of kernel page tables */
1364Srgrimes
13783366Sjulian	.globl	proc0uarea, proc0kstack
13899741Sobrienproc0uarea:	.long	0		/* address of proc 0 uarea space */
13999741Sobrienproc0kstack:	.long	0		/* address of proc 0 kstack space */
14099741Sobrienp0upa:		.long	0		/* phys addr of proc0's UAREA */
14199741Sobrienp0kpa:		.long	0		/* phys addr of proc0's STACK */
142134Sdg
14399741Sobrienvm86phystk:	.long	0		/* PA of vm86/bios stack */
14437889Sjlemon
14573011Sjake	.globl	vm86paddr, vm86pa
14699741Sobrienvm86paddr:	.long	0		/* address of vm86 region */
14799741Sobrienvm86pa:		.long	0		/* phys addr of vm86 region */
14834840Sjlemon
14943434Skato#ifdef PC98
15073011Sjake	.globl	pc98_system_parameter
15173011Sjakepc98_system_parameter:
15243434Skato	.space	0x240
15343434Skato#endif
15415428Sphk
15515392Sphk/**********************************************************************
15615392Sphk *
15715392Sphk * Some handy macros
15815392Sphk *
159556Srgrimes */
160134Sdg
16115392Sphk#define R(foo) ((foo)-KERNBASE)
16215392Sphk
16315392Sphk#define ALLOCPAGES(foo) \
16415392Sphk	movl	R(physfree), %esi ; \
16515543Sphk	movl	$((foo)*PAGE_SIZE), %eax ; \
16615392Sphk	addl	%esi, %eax ; \
16715392Sphk	movl	%eax, R(physfree) ; \
16815392Sphk	movl	%esi, %edi ; \
16915543Sphk	movl	$((foo)*PAGE_SIZE),%ecx ; \
17015392Sphk	xorl	%eax,%eax ; \
17115428Sphk	cld ; \
17215428Sphk	rep ; \
17315428Sphk	stosb
17415392Sphk
175134Sdg/*
17615392Sphk * fillkpt
17715565Sphk *	eax = page frame address
17815565Sphk *	ebx = index into page table
17915392Sphk *	ecx = how many pages to map
18015565Sphk * 	base = base address of page dir/table
18115565Sphk *	prot = protection bits
182134Sdg */
18315565Sphk#define	fillkpt(base, prot)		  \
184111299Sjake	shll	$PTESHIFT,%ebx		; \
18519621Sdyson	addl	base,%ebx		; \
18619621Sdyson	orl	$PG_V,%eax		; \
18719621Sdyson	orl	prot,%eax		; \
18815565Sphk1:	movl	%eax,(%ebx)		; \
18915565Sphk	addl	$PAGE_SIZE,%eax		; /* increment physical address */ \
190111299Sjake	addl	$PTESIZE,%ebx		; /* next pte */ \
19115428Sphk	loop	1b
19215392Sphk
19315565Sphk/*
19415565Sphk * fillkptphys(prot)
19515565Sphk *	eax = physical address
19615565Sphk *	ecx = how many pages to map
19715565Sphk *	prot = protection bits
19815565Sphk */
19915565Sphk#define	fillkptphys(prot)		  \
20015565Sphk	movl	%eax, %ebx		; \
20115565Sphk	shrl	$PAGE_SHIFT, %ebx	; \
20273011Sjake	fillkpt(R(KPTphys), prot)
20315565Sphk
20415392Sphk	.text
20515392Sphk/**********************************************************************
20615392Sphk *
20715392Sphk * This is where the bootblocks start us, set the ball rolling...
20815392Sphk *
20915392Sphk */
2101321SdgNON_GPROF_ENTRY(btext)
2114Srgrimes
21224112Skato#ifdef PC98
21324112Skato	/* save SYSTEM PARAMETER for resume (NS/T or other) */
21443434Skato	movl	$0xa1400,%esi
21573011Sjake	movl	$R(pc98_system_parameter),%edi
21643434Skato	movl	$0x0240,%ecx
21724112Skato	cld
21824112Skato	rep
21924112Skato	movsb
22024112Skato#else	/* IBM-PC */
22115392Sphk/* Tell the bios to warmboot next time */
22215392Sphk	movw	$0x1234,0x472
22354128Skato#endif	/* PC98 */
22415392Sphk
22515428Sphk/* Set up a real frame in case the double return in newboot is executed. */
2263384Srgrimes	pushl	%ebp
2273384Srgrimes	movl	%esp, %ebp
2283384Srgrimes
22915392Sphk/* Don't trust what the BIOS gives for eflags. */
2305603Sbde	pushl	$PSL_KERNEL
2312486Sdg	popfl
23215428Sphk
23315428Sphk/*
23415428Sphk * Don't trust what the BIOS gives for %fs and %gs.  Trust the bootstrap
23515428Sphk * to set %cs, %ds, %es and %ss.
23615428Sphk */
23715428Sphk	mov	%ds, %ax
2384217Sphk	mov	%ax, %fs
2394217Sphk	mov	%ax, %gs
2404217Sphk
241118186Sbde/*
242118186Sbde * Clear the bss.  Not all boot programs do it, and it is our job anyway.
243118186Sbde *
244118186Sbde * XXX we don't check that there is memory for our bss and page tables
245118186Sbde * before using it.
246118186Sbde *
247118186Sbde * Note: we must be careful to not overwrite an active gdt or idt.  They
248118186Sbde * inactive from now until we switch to new ones, since we don't load any
249118186Sbde * more segment registers or permit interrupts until after the switch.
250118186Sbde */
251118186Sbde	movl	$R(end),%ecx
252118186Sbde	movl	$R(edata),%edi
253118186Sbde	subl	%edi,%ecx
254118186Sbde	xorl	%eax,%eax
255118186Sbde	cld
256118186Sbde	rep
257118186Sbde	stosb
258118186Sbde
25915392Sphk	call	recover_bootinfo
26015392Sphk
26115428Sphk/* Get onto a stack that we can trust. */
26215428Sphk/*
26315428Sphk * XXX this step is delayed in case recover_bootinfo needs to return via
26415428Sphk * the old stack, but it need not be, since recover_bootinfo actually
26515428Sphk * returns via the old frame.
26615428Sphk */
267118154Sbde	movl	$R(tmpstk),%esp
26815392Sphk
26924112Skato#ifdef PC98
27043447Skato	/* pc98_machine_type & M_EPSON_PC98 */
27173011Sjake	testb	$0x02,R(pc98_system_parameter)+220
27224112Skato	jz	3f
27343447Skato	/* epson_machine_id <= 0x0b */
27473011Sjake	cmpb	$0x0b,R(pc98_system_parameter)+224
27524112Skato	ja	3f
27624112Skato
27724112Skato	/* count up memory */
27824112Skato	movl	$0x100000,%eax		/* next, talley remaining memory */
27924112Skato	movl	$0xFFF-0x100,%ecx
28024112Skato1:	movl	0(%eax),%ebx		/* save location to check */
28124112Skato	movl	$0xa55a5aa5,0(%eax)	/* write test pattern */
28224112Skato	cmpl	$0xa55a5aa5,0(%eax)	/* does not check yet for rollover */
28324112Skato	jne	2f
28424112Skato	movl	%ebx,0(%eax)		/* restore memory */
28524112Skato	addl	$PAGE_SIZE,%eax
28624112Skato	loop	1b
28724112Skato2:	subl	$0x100000,%eax
28824112Skato	shrl	$17,%eax
28973011Sjake	movb	%al,R(pc98_system_parameter)+1
29024112Skato3:
29158786Skato
29273011Sjake	movw	R(pc98_system_parameter+0x86),%ax
29373011Sjake	movw	%ax,R(cpu_id)
29424112Skato#endif
29524112Skato
29615392Sphk	call	identify_cpu
29715392Sphk	call	create_pagetables
29815392Sphk
29927993Sdyson/*
30027993Sdyson * If the CPU has support for VME, turn it on.
30127993Sdyson */
30273011Sjake	testl	$CPUID_VME, R(cpu_feature)
30327993Sdyson	jz	1f
30427993Sdyson	movl	%cr4, %eax
30527993Sdyson	orl	$CR4_VME, %eax
30627993Sdyson	movl	%eax, %cr4
30727993Sdyson1:
30827993Sdyson
30915392Sphk/* Now enable paging */
310112841Sjake#ifdef PAE
311112841Sjake	movl	R(IdlePDPT), %eax
312112841Sjake	movl	%eax, %cr3
313112841Sjake	movl	%cr4, %eax
314112841Sjake	orl	$CR4_PAE, %eax
315112841Sjake	movl	%eax, %cr4
316112841Sjake#else
31773011Sjake	movl	R(IdlePTD), %eax
31899741Sobrien	movl	%eax,%cr3		/* load ptd addr into mmu */
319112841Sjake#endif
32099741Sobrien	movl	%cr0,%eax		/* get control word */
32199741Sobrien	orl	$CR0_PE|CR0_PG,%eax	/* enable paging */
32299741Sobrien	movl	%eax,%cr0		/* and let's page NOW! */
32315392Sphk
32499741Sobrien	pushl	$begin			/* jump to high virtualized address */
32515392Sphk	ret
32615392Sphk
32715392Sphk/* now running relocated at KERNBASE where the system is linked to run */
32815392Sphkbegin:
32915392Sphk	/* set up bootstrap stack */
33099741Sobrien	movl	proc0kstack,%eax	/* location of in-kernel stack */
33183366Sjulian			/* bootstrap stack end location */
33283366Sjulian	leal	(KSTACK_PAGES*PAGE_SIZE-PCB_SIZE)(%eax),%esp
33365815Sbde
33499741Sobrien	xorl	%ebp,%ebp		/* mark end of frames */
33565815Sbde
336112841Sjake#ifdef PAE
337112841Sjake	movl	IdlePDPT,%esi
338112841Sjake#else
33973011Sjake	movl	IdlePTD,%esi
340112841Sjake#endif
34183366Sjulian	movl	%esi,(KSTACK_PAGES*PAGE_SIZE-PCB_SIZE+PCB_CR3)(%eax)
34215392Sphk
34399741Sobrien	pushl	physfree		/* value of first for init386(first) */
34499741Sobrien	call	init386			/* wire 386 chip for unix operation */
34515392Sphk
34665815Sbde	/*
34765815Sbde	 * Clean up the stack in a way that db_numargs() understands, so
34865815Sbde	 * that backtraces in ddb don't underrun the stack.  Traps for
34965815Sbde	 * inaccessible memory are more fatal than usual this early.
35065815Sbde	 */
35165815Sbde	addl	$4,%esp
35265815Sbde
35399741Sobrien	call	mi_startup		/* autoconfiguration, mountroot etc */
35465815Sbde	/* NOTREACHED */
35599741Sobrien	addl	$0,%esp			/* for db_numargs() again */
35615392Sphk
35724691Speter/*
35815392Sphk * Signal trampoline, copied to top of user stack
35915392Sphk */
36015392SphkNON_GPROF_ENTRY(sigcode)
361107521Sdeischen	calll	*SIGF_HANDLER(%esp)
362107521Sdeischen	leal	SIGF_UC(%esp),%eax	/* get ucontext */
36315392Sphk	pushl	%eax
36452140Sluoqi	testl	$PSL_VM,UC_EFLAGS(%eax)
365107521Sdeischen	jne	1f
36699741Sobrien	movl	UC_GS(%eax),%gs		/* restore %gs */
367107521Sdeischen1:
36852140Sluoqi	movl	$SYS_sigreturn,%eax
36999741Sobrien	pushl	%eax			/* junk to fake return addr. */
37099741Sobrien	int	$0x80			/* enter kernel with args */
371107521Sdeischen					/* on stack */
372107521Sdeischen1:
373107521Sdeischen	jmp	1b
37452140Sluoqi
375105950Speter#ifdef COMPAT_FREEBSD4
376105950Speter	ALIGN_TEXT
377105950Speterfreebsd4_sigcode:
378107521Sdeischen	calll	*SIGF_HANDLER(%esp)
379107521Sdeischen	leal	SIGF_UC4(%esp),%eax	/* get ucontext */
380105950Speter	pushl	%eax
381105950Speter	testl	$PSL_VM,UC4_EFLAGS(%eax)
382107521Sdeischen	jne	1f
383105950Speter	movl	UC4_GS(%eax),%gs	/* restore %gs */
384107521Sdeischen1:
385105950Speter	movl	$344,%eax		/* 4.x SYS_sigreturn */
386105950Speter	pushl	%eax			/* junk to fake return addr. */
387105950Speter	int	$0x80			/* enter kernel with args */
388107521Sdeischen					/* on stack */
389107521Sdeischen1:
390107521Sdeischen	jmp	1b
391105950Speter#endif
392105950Speter
39390132Sbde#ifdef COMPAT_43
39425083Sjdp	ALIGN_TEXT
39573011Sjakeosigcode:
39699741Sobrien	call	*SIGF_HANDLER(%esp)	/* call signal handler */
39799741Sobrien	lea	SIGF_SC(%esp),%eax	/* get sigcontext */
39852140Sluoqi	pushl	%eax
39952140Sluoqi	testl	$PSL_VM,SC_PS(%eax)
40052140Sluoqi	jne	9f
40199741Sobrien	movl	SC_GS(%eax),%gs		/* restore %gs */
40252140Sluoqi9:
403105950Speter	movl	$103,%eax		/* 3.x SYS_sigreturn */
40499741Sobrien	pushl	%eax			/* junk to fake return addr. */
40599741Sobrien	int	$0x80			/* enter kernel with args */
40652140Sluoqi0:	jmp	0b
40790132Sbde#endif /* COMPAT_43 */
40852140Sluoqi
40952140Sluoqi	ALIGN_TEXT
41073011Sjakeesigcode:
41115392Sphk
41215392Sphk	.data
413105950Speter	.globl	szsigcode
41473011Sjakeszsigcode:
41573011Sjake	.long	esigcode-sigcode
416105950Speter#ifdef COMPAT_FREEBSD4
417105950Speter	.globl	szfreebsd4_sigcode
418105950Speterszfreebsd4_sigcode:
419105950Speter	.long	esigcode-freebsd4_sigcode
420105950Speter#endif
42190132Sbde#ifdef COMPAT_43
422105950Speter	.globl	szosigcode
42373011Sjakeszosigcode:
42473011Sjake	.long	esigcode-osigcode
42590132Sbde#endif
42615428Sphk	.text
42715392Sphk
42815392Sphk/**********************************************************************
42915392Sphk *
43015392Sphk * Recover the bootinfo passed to us from the boot program
43115392Sphk *
43215392Sphk */
43315392Sphkrecover_bootinfo:
43415392Sphk	/*
4353284Srgrimes	 * This code is called in different ways depending on what loaded
4363284Srgrimes	 * and started the kernel.  This is used to detect how we get the
4373284Srgrimes	 * arguments from the other code and what we do with them.
4383284Srgrimes	 *
4393284Srgrimes	 * Old disk boot blocks:
4403284Srgrimes	 *	(*btext)(howto, bootdev, cyloffset, esym);
4413284Srgrimes	 *	[return address == 0, and can NOT be returned to]
4423284Srgrimes	 *	[cyloffset was not supported by the FreeBSD boot code
4433284Srgrimes	 *	 and always passed in as 0]
4443284Srgrimes	 *	[esym is also known as total in the boot code, and
4453284Srgrimes	 *	 was never properly supported by the FreeBSD boot code]
4463284Srgrimes	 *
4473284Srgrimes	 * Old diskless netboot code:
4483284Srgrimes	 *	(*btext)(0,0,0,0,&nfsdiskless,0,0,0);
4493284Srgrimes	 *	[return address != 0, and can NOT be returned to]
4503284Srgrimes	 *	If we are being booted by this code it will NOT work,
4513284Srgrimes	 *	so we are just going to halt if we find this case.
4523284Srgrimes	 *
4533284Srgrimes	 * New uniform boot code:
4543284Srgrimes	 *	(*btext)(howto, bootdev, 0, 0, 0, &bootinfo)
4553284Srgrimes	 *	[return address != 0, and can be returned to]
4563284Srgrimes	 *
4573284Srgrimes	 * There may seem to be a lot of wasted arguments in here, but
4583384Srgrimes	 * that is so the newer boot code can still load very old kernels
4593384Srgrimes	 * and old boot code can load new kernels.
4604Srgrimes	 */
4613284Srgrimes
4623284Srgrimes	/*
4633284Srgrimes	 * The old style disk boot blocks fake a frame on the stack and
4643284Srgrimes	 * did an lret to get here.  The frame on the stack has a return
4653284Srgrimes	 * address of 0.
4663284Srgrimes	 */
4673384Srgrimes	cmpl	$0,4(%ebp)
46815392Sphk	je	olddiskboot
4693284Srgrimes
4703284Srgrimes	/*
4713284Srgrimes	 * We have some form of return address, so this is either the
4723284Srgrimes	 * old diskless netboot code, or the new uniform code.  That can
47315428Sphk	 * be detected by looking at the 5th argument, if it is 0
47415428Sphk	 * we are being booted by the new uniform boot code.
4753284Srgrimes	 */
4763384Srgrimes	cmpl	$0,24(%ebp)
47715392Sphk	je	newboot
4783284Srgrimes
4793284Srgrimes	/*
4803284Srgrimes	 * Seems we have been loaded by the old diskless boot code, we
4813284Srgrimes	 * don't stand a chance of running as the diskless structure
4823284Srgrimes	 * changed considerably between the two, so just halt.
4833284Srgrimes	 */
4843284Srgrimes	 hlt
4853284Srgrimes
4863284Srgrimes	/*
4873384Srgrimes	 * We have been loaded by the new uniform boot code.
48815428Sphk	 * Let's check the bootinfo version, and if we do not understand
4893384Srgrimes	 * it we return to the loader with a status of 1 to indicate this error
4903284Srgrimes	 */
49115392Sphknewboot:
4923384Srgrimes	movl	28(%ebp),%ebx		/* &bootinfo.version */
4935908Sbde	movl	BI_VERSION(%ebx),%eax
4943384Srgrimes	cmpl	$1,%eax			/* We only understand version 1 */
4953384Srgrimes	je	1f
4963384Srgrimes	movl	$1,%eax			/* Return status */
4973384Srgrimes	leave
49815428Sphk	/*
49915428Sphk	 * XXX this returns to our caller's caller (as is required) since
50015428Sphk	 * we didn't set up a frame and our caller did.
50115428Sphk	 */
5023384Srgrimes	ret
5033284Srgrimes
5043384Srgrimes1:
5053284Srgrimes	/*
5063384Srgrimes	 * If we have a kernelname copy it in
5073384Srgrimes	 */
5085908Sbde	movl	BI_KERNELNAME(%ebx),%esi
5093384Srgrimes	cmpl	$0,%esi
5109344Sdg	je	2f			/* No kernelname */
5119344Sdg	movl	$MAXPATHLEN,%ecx	/* Brute force!!! */
51273011Sjake	movl	$R(kernelname),%edi
5139344Sdg	cmpb	$'/',(%esi)		/* Make sure it starts with a slash */
5149344Sdg	je	1f
5159344Sdg	movb	$'/',(%edi)
5169344Sdg	incl	%edi
5179344Sdg	decl	%ecx
5189344Sdg1:
5193384Srgrimes	cld
5203384Srgrimes	rep
5213384Srgrimes	movsb
5223384Srgrimes
5239344Sdg2:
52415428Sphk	/*
5255908Sbde	 * Determine the size of the boot loader's copy of the bootinfo
5265908Sbde	 * struct.  This is impossible to do properly because old versions
5275908Sbde	 * of the struct don't contain a size field and there are 2 old
5285908Sbde	 * versions with the same version number.
5294600Sphk	 */
5305908Sbde	movl	$BI_ENDCOMMON,%ecx	/* prepare for sizeless version */
5315908Sbde	testl	$RB_BOOTINFO,8(%ebp)	/* bi_size (and bootinfo) valid? */
5325908Sbde	je	got_bi_size		/* no, sizeless version */
5335908Sbde	movl	BI_SIZE(%ebx),%ecx
5345908Sbdegot_bi_size:
5355908Sbde
53615428Sphk	/*
5375908Sbde	 * Copy the common part of the bootinfo struct
5385908Sbde	 */
5394600Sphk	movl	%ebx,%esi
54073011Sjake	movl	$R(bootinfo),%edi
5415908Sbde	cmpl	$BOOTINFO_SIZE,%ecx
5425908Sbde	jbe	got_common_bi_size
5434600Sphk	movl	$BOOTINFO_SIZE,%ecx
5445908Sbdegot_common_bi_size:
5454600Sphk	cld
5464600Sphk	rep
5474600Sphk	movsb
5484600Sphk
54938063Smsmith#ifdef NFS_ROOT
55025837Stegge#ifndef BOOTP_NFSV3
5513384Srgrimes	/*
5523384Srgrimes	 * If we have a nfs_diskless structure copy it in
5533384Srgrimes	 */
5545908Sbde	movl	BI_NFS_DISKLESS(%ebx),%esi
5553384Srgrimes	cmpl	$0,%esi
55615428Sphk	je	olddiskboot
55773011Sjake	movl	$R(nfs_diskless),%edi
5583384Srgrimes	movl	$NFSDISKLESS_SIZE,%ecx
5593384Srgrimes	cld
5603384Srgrimes	rep
5613384Srgrimes	movsb
56273011Sjake	movl	$R(nfs_diskless_valid),%edi
5633795Sphk	movl	$1,(%edi)
5643406Sdg#endif
56525837Stegge#endif
5663384Srgrimes
5673384Srgrimes	/*
5683284Srgrimes	 * The old style disk boot.
5693284Srgrimes	 *	(*btext)(howto, bootdev, cyloffset, esym);
5703384Srgrimes	 * Note that the newer boot code just falls into here to pick
5713384Srgrimes	 * up howto and bootdev, cyloffset and esym are no longer used
5723284Srgrimes	 */
57315392Sphkolddiskboot:
5743384Srgrimes	movl	8(%ebp),%eax
57573011Sjake	movl	%eax,R(boothowto)
5763384Srgrimes	movl	12(%ebp),%eax
57773011Sjake	movl	%eax,R(bootdev)
5782783Ssos
57915392Sphk	ret
5803258Sdg
5811321Sdg
58215392Sphk/**********************************************************************
58315392Sphk *
58415392Sphk * Identify the CPU and initialize anything special about it
58515392Sphk *
58615392Sphk */
58715392Sphkidentify_cpu:
58815392Sphk
5891998Swollman	/* Try to toggle alignment check flag; does not exist on 386. */
5901998Swollman	pushfl
5911998Swollman	popl	%eax
5921998Swollman	movl	%eax,%ecx
5931998Swollman	orl	$PSL_AC,%eax
5941998Swollman	pushl	%eax
5951998Swollman	popfl
5961998Swollman	pushfl
5971998Swollman	popl	%eax
5981998Swollman	xorl	%ecx,%eax
5991998Swollman	andl	$PSL_AC,%eax
6001998Swollman	pushl	%ecx
6011998Swollman	popfl
6021998Swollman
6031998Swollman	testl	%eax,%eax
60424112Skato	jnz	try486
60524112Skato
60624112Skato	/* NexGen CPU does not have aligment check flag. */
60724112Skato	pushfl
60824112Skato	movl	$0x5555, %eax
60924112Skato	xorl	%edx, %edx
61024112Skato	movl	$2, %ecx
61124112Skato	clc
61224112Skato	divl	%ecx
61324112Skato	jz	trynexgen
61424112Skato	popfl
61573011Sjake	movl	$CPU_386,R(cpu)
61613081Sdg	jmp	3f
6171998Swollman
61824112Skatotrynexgen:
61927424Skato	popfl
62073011Sjake	movl	$CPU_NX586,R(cpu)
62173011Sjake	movl	$0x4778654e,R(cpu_vendor)	# store vendor string
62273011Sjake	movl	$0x72446e65,R(cpu_vendor+4)
62373011Sjake	movl	$0x6e657669,R(cpu_vendor+8)
62473011Sjake	movl	$0,R(cpu_vendor+12)
62524112Skato	jmp	3f
62624112Skato
62724112Skatotry486:	/* Try to toggle identification flag; does not exist on early 486s. */
6281998Swollman	pushfl
6291998Swollman	popl	%eax
6301998Swollman	movl	%eax,%ecx
6311998Swollman	xorl	$PSL_ID,%eax
6321998Swollman	pushl	%eax
6331998Swollman	popfl
6341998Swollman	pushfl
6351998Swollman	popl	%eax
6361998Swollman	xorl	%ecx,%eax
6371998Swollman	andl	$PSL_ID,%eax
6381998Swollman	pushl	%ecx
6391998Swollman	popfl
6401998Swollman
6411998Swollman	testl	%eax,%eax
64224112Skato	jnz	trycpuid
64373011Sjake	movl	$CPU_486,R(cpu)
6442495Spst
64524112Skato	/*
64624112Skato	 * Check Cyrix CPU
64724112Skato	 * Cyrix CPUs do not change the undefined flags following
64824112Skato	 * execution of the divide instruction which divides 5 by 2.
64924112Skato	 *
65024112Skato	 * Note: CPUID is enabled on M2, so it passes another way.
65124112Skato	 */
65224112Skato	pushfl
65324112Skato	movl	$0x5555, %eax
65424112Skato	xorl	%edx, %edx
65524112Skato	movl	$2, %ecx
65624112Skato	clc
65724112Skato	divl	%ecx
65824112Skato	jnc	trycyrix
65924112Skato	popfl
66024112Skato	jmp	3f		/* You may use Intel CPU. */
6612495Spst
66224112Skatotrycyrix:
66324112Skato	popfl
66424112Skato	/*
66524112Skato	 * IBM Bluelighting CPU also doesn't change the undefined flags.
66624112Skato	 * Because IBM doesn't disclose the information for Bluelighting
66724112Skato	 * CPU, we couldn't distinguish it from Cyrix's (including IBM
66824112Skato	 * brand of Cyrix CPUs).
66924112Skato	 */
67073011Sjake	movl	$0x69727943,R(cpu_vendor)	# store vendor string
67173011Sjake	movl	$0x736e4978,R(cpu_vendor+4)
67273011Sjake	movl	$0x64616574,R(cpu_vendor+8)
67313014Sdg	jmp	3f
6741998Swollman
67524112Skatotrycpuid:	/* Use the `cpuid' instruction. */
6761998Swollman	xorl	%eax,%eax
67769006Smarkm	cpuid					# cpuid 0
67873011Sjake	movl	%eax,R(cpu_high)		# highest capability
67973011Sjake	movl	%ebx,R(cpu_vendor)		# store vendor string
68073011Sjake	movl	%edx,R(cpu_vendor+4)
68173011Sjake	movl	%ecx,R(cpu_vendor+8)
68273011Sjake	movb	$0,R(cpu_vendor+12)
6831998Swollman
6841998Swollman	movl	$1,%eax
68569006Smarkm	cpuid					# cpuid 1
68673011Sjake	movl	%eax,R(cpu_id)			# store cpu_id
687109696Sjhb	movl	%ebx,R(cpu_procinfo)		# store cpu_procinfo
68873011Sjake	movl	%edx,R(cpu_feature)		# store cpu_feature
6896308Sphk	rorl	$8,%eax				# extract family type
6901998Swollman	andl	$15,%eax
6911998Swollman	cmpl	$5,%eax
6921998Swollman	jae	1f
6931998Swollman
6941998Swollman	/* less than Pentium; must be 486 */
69573011Sjake	movl	$CPU_486,R(cpu)
69613000Sdg	jmp	3f
69713000Sdg1:
69813000Sdg	/* a Pentium? */
69913000Sdg	cmpl	$5,%eax
70013000Sdg	jne	2f
70173011Sjake	movl	$CPU_586,R(cpu)
70213000Sdg	jmp	3f
703556Srgrimes2:
70413000Sdg	/* Greater than Pentium...call it a Pentium Pro */
70573011Sjake	movl	$CPU_686,R(cpu)
70613000Sdg3:
70715392Sphk	ret
708556Srgrimes
7094Srgrimes
71015392Sphk/**********************************************************************
711570Srgrimes *
71215428Sphk * Create the first page directory and its page tables.
71315392Sphk *
714570Srgrimes */
715570Srgrimes
71615392Sphkcreate_pagetables:
71715392Sphk
71815428Sphk/* Find end of kernel image (rounded up to a page boundary). */
71915392Sphk	movl	$R(_end),%esi
7204Srgrimes
72161422Sbde/* Include symbols, if any. */
72273011Sjake	movl	R(bootinfo+BI_ESYMTAB),%edi
7235908Sbde	testl	%edi,%edi
72415428Sphk	je	over_symalloc
7255908Sbde	movl	%edi,%esi
7265908Sbde	movl	$KERNBASE,%edi
72773011Sjake	addl	%edi,R(bootinfo+BI_SYMTAB)
72873011Sjake	addl	%edi,R(bootinfo+BI_ESYMTAB)
72915428Sphkover_symalloc:
7305908Sbde
73140081Smsmith/* If we are told where the end of the kernel space is, believe it. */
73273011Sjake	movl	R(bootinfo+BI_KERNEND),%edi
73340081Smsmith	testl	%edi,%edi
73440081Smsmith	je	no_kernend
73540081Smsmith	movl	%edi,%esi
73640081Smsmithno_kernend:
737120654Speter
738120654Speter	addl	$PDRMASK,%esi		/* Play conservative for now, and */
739120654Speter	andl	$~PDRMASK,%esi		/*   ... wrap to next 4M. */
74073011Sjake	movl	%esi,R(KERNend)		/* save end of kernel */
74115428Sphk	movl	%esi,R(physfree)	/* next free page is at end of kernel */
742608Srgrimes
74315392Sphk/* Allocate Kernel Page Tables */
74415392Sphk	ALLOCPAGES(NKPT)
74573011Sjake	movl	%esi,R(KPTphys)
746757Sdg
74715392Sphk/* Allocate Page Table Directory */
748112841Sjake#ifdef PAE
749112841Sjake	/* XXX only need 32 bytes (easier for now) */
750112841Sjake	ALLOCPAGES(1)
751112841Sjake	movl	%esi,R(IdlePDPT)
752112841Sjake#endif
753111363Sjake	ALLOCPAGES(NPGPTD)
75473011Sjake	movl	%esi,R(IdlePTD)
7554Srgrimes
75615392Sphk/* Allocate UPAGES */
75783366Sjulian	ALLOCPAGES(UAREA_PAGES)
75817120Sbde	movl	%esi,R(p0upa)
75915392Sphk	addl	$KERNBASE, %esi
76083366Sjulian	movl	%esi, R(proc0uarea)
7614Srgrimes
76283366Sjulian	ALLOCPAGES(KSTACK_PAGES)
76383366Sjulian	movl	%esi,R(p0kpa)
76483366Sjulian	addl	$KERNBASE, %esi
76583366Sjulian	movl	%esi, R(proc0kstack)
76683366Sjulian
76737889Sjlemon	ALLOCPAGES(1)			/* vm86/bios stack */
76837889Sjlemon	movl	%esi,R(vm86phystk)
76937889Sjlemon
77037889Sjlemon	ALLOCPAGES(3)			/* pgtable + ext + IOPAGES */
77173011Sjake	movl	%esi,R(vm86pa)
77234840Sjlemon	addl	$KERNBASE, %esi
77373011Sjake	movl	%esi, R(vm86paddr)
77434840Sjlemon
77526812Speter#ifdef SMP
77625164Speter/* Allocate cpu0's private data page */
77725164Speter	ALLOCPAGES(1)
77825164Speter	movl	%esi,R(cpu0pp)
77925164Speter	addl	$KERNBASE, %esi
78073011Sjake	movl	%esi, R(cpu0prvpage)	/* relocated to KVM space */
78125164Speter
78246129Sluoqi/* Allocate SMP page table page */
78325164Speter	ALLOCPAGES(1)
78446129Sluoqi	movl	%esi,R(SMPptpa)
78525164Speter	addl	$KERNBASE, %esi
78673011Sjake	movl	%esi, R(SMPpt)		/* relocated to KVM space */
78726812Speter#endif	/* SMP */
78825164Speter
789120654Speter/* Map read-only from zero to the beginning of the kernel text section */
79015565Sphk	xorl	%eax, %eax
79119621Sdyson	xorl	%edx,%edx
792120654Speter	movl	$R(btext),%ecx
79315565Sphk	addl	$PAGE_MASK,%ecx
79415565Sphk	shrl	$PAGE_SHIFT,%ecx
79519621Sdyson	fillkptphys(%edx)
796757Sdg
797120654Speter/*
798120654Speter * Enable PSE and PGE.
799120654Speter */
800120654Speter#ifndef DISABLE_PSE
801120654Speter	testl	$CPUID_PSE, R(cpu_feature)
802120654Speter	jz	1f
803120654Speter	movl	$PG_PS, R(pseflag)
804120654Speter	movl	%cr4, %eax
805120654Speter	orl	$CR4_PSE, %eax
806120654Speter	movl	%eax, %cr4
807120654Speter1:
808120654Speter#endif
809120654Speter#ifndef DISABLE_PG_G
810120654Speter	testl	$CPUID_PGE, R(cpu_feature)
811120654Speter	jz	2f
812120654Speter	movl	$PG_G, R(pgeflag)
813120654Speter	movl	%cr4, %eax
814120654Speter	orl	$CR4_PGE, %eax
815120654Speter	movl	%eax, %cr4
816120654Speter2:
817120654Speter#endif
818120654Speter
819120654Speter/*
820120654Speter * Write page tables for the kernel starting at btext and
821120654Speter * until the end.  Make sure to map read+write.  We do this even
822120654Speter * if we've enabled PSE above, we'll just switch the corresponding kernel
823120654Speter * PDEs before we turn on paging.
824120654Speter *
825120654Speter * XXX: We waste some pages here in the PSE case!  DON'T BLINDLY REMOVE
826120654Speter * THIS!  SMP needs the page table to be there to map the kernel P==V.
827120654Speter */
828120654Speter	movl	$R(btext),%eax
82915694Sphk	addl	$PAGE_MASK, %eax
83015694Sphk	andl	$~PAGE_MASK, %eax
83119621Sdyson	movl	$PG_RW,%edx
83299862Speter	movl	R(KERNend),%ecx
833757Sdg	subl	%eax,%ecx
83415543Sphk	shrl	$PAGE_SHIFT,%ecx
83519621Sdyson	fillkptphys(%edx)
836757Sdg
83715428Sphk/* Map page directory. */
838112841Sjake#ifdef PAE
839112841Sjake	movl	R(IdlePDPT), %eax
840112841Sjake	movl	$1, %ecx
841112841Sjake	fillkptphys($PG_RW)
842112841Sjake#endif
843112841Sjake
84473011Sjake	movl	R(IdlePTD), %eax
845111363Sjake	movl	$NPGPTD, %ecx
84619621Sdyson	fillkptphys($PG_RW)
847757Sdg
84817120Sbde/* Map proc0's UPAGES in the physical way ... */
84917120Sbde	movl	R(p0upa), %eax
85083366Sjulian	movl	$(UAREA_PAGES), %ecx
85119621Sdyson	fillkptphys($PG_RW)
8524Srgrimes
85383366Sjulian/* Map proc0's KSTACK in the physical way ... */
85483366Sjulian	movl	R(p0kpa), %eax
85583366Sjulian	movl	$(KSTACK_PAGES), %ecx
85683366Sjulian	fillkptphys($PG_RW)
85783366Sjulian
85815565Sphk/* Map ISA hole */
85915565Sphk	movl	$ISA_HOLE_START, %eax
86015565Sphk	movl	$ISA_HOLE_LENGTH>>PAGE_SHIFT, %ecx
86122130Sdg	fillkptphys($PG_RW)
86215565Sphk
86334840Sjlemon/* Map space for the vm86 region */
86437889Sjlemon	movl	R(vm86phystk), %eax
86534840Sjlemon	movl	$4, %ecx
86634840Sjlemon	fillkptphys($PG_RW)
86734840Sjlemon
86834840Sjlemon/* Map page 0 into the vm86 page table */
86934840Sjlemon	movl	$0, %eax
87034840Sjlemon	movl	$0, %ebx
87134840Sjlemon	movl	$1, %ecx
87273011Sjake	fillkpt(R(vm86pa), $PG_RW|PG_U)
87334840Sjlemon
87434840Sjlemon/* ...likewise for the ISA hole */
87534840Sjlemon	movl	$ISA_HOLE_START, %eax
87634840Sjlemon	movl	$ISA_HOLE_START>>PAGE_SHIFT, %ebx
87734840Sjlemon	movl	$ISA_HOLE_LENGTH>>PAGE_SHIFT, %ecx
87873011Sjake	fillkpt(R(vm86pa), $PG_RW|PG_U)
87934840Sjlemon
88026812Speter#ifdef SMP
88126812Speter/* Map cpu0's private page into global kmem (4K @ cpu0prvpage) */
88225164Speter	movl	R(cpu0pp), %eax
88325164Speter	movl	$1, %ecx
88425164Speter	fillkptphys($PG_RW)
88525164Speter
88646129Sluoqi/* Map SMP page table page into global kmem FWIW */
88746129Sluoqi	movl	R(SMPptpa), %eax
88825164Speter	movl	$1, %ecx
88925164Speter	fillkptphys($PG_RW)
89025164Speter
89146129Sluoqi/* Map the private page into the SMP page table */
89225164Speter	movl	R(cpu0pp), %eax
89325164Speter	movl	$0, %ebx		/* pte offset = 0 */
89425164Speter	movl	$1, %ecx		/* one private page coming right up */
89546129Sluoqi	fillkpt(R(SMPptpa), $PG_RW)
89625164Speter
89726812Speter/* ... and put the page table table in the pde. */
89846129Sluoqi	movl	R(SMPptpa), %eax
89925164Speter	movl	$MPPTDI, %ebx
90025164Speter	movl	$1, %ecx
90173011Sjake	fillkpt(R(IdlePTD), $PG_RW)
90234840Sjlemon
90334840Sjlemon/* Fakeup VA for the local apic to allow early traps. */
90434840Sjlemon	ALLOCPAGES(1)
90534840Sjlemon	movl	%esi, %eax
90646129Sluoqi	movl	$(NPTEPG-1), %ebx	/* pte offset = NTEPG-1 */
90734840Sjlemon	movl	$1, %ecx		/* one private pt coming right up */
90846129Sluoqi	fillkpt(R(SMPptpa), $PG_RW)
90926812Speter#endif	/* SMP */
91025164Speter
91115392Sphk/* install a pde for temporary double map of bottom of VA */
91273011Sjake	movl	R(KPTphys), %eax
91315565Sphk	xorl	%ebx, %ebx
91474283Speter	movl	$NKPT, %ecx
91573011Sjake	fillkpt(R(IdlePTD), $PG_RW)
9164Srgrimes
917120654Speter/*
918120654Speter * For the non-PSE case, install PDEs for PTs covering the kernel.
919120654Speter * For the PSE case, do the same, but clobber the ones corresponding
920120654Speter * to the kernel (from btext to KERNend) with 4M ('PS') PDEs immediately
921120654Speter * after.
922120654Speter */
92373011Sjake	movl	R(KPTphys), %eax
92415565Sphk	movl	$KPTDI, %ebx
92515565Sphk	movl	$NKPT, %ecx
92673011Sjake	fillkpt(R(IdlePTD), $PG_RW)
927120654Speter	cmpl	$0,R(pseflag)
928120654Speter	je	done_pde
9294Srgrimes
930120654Speter	movl	R(KERNend), %ecx
931120654Speter	movl	$KERNLOAD, %eax
932120654Speter	subl	%eax, %ecx
933120654Speter	shrl	$PDRSHIFT, %ecx
934120654Speter	movl	$(KPTDI+(KERNLOAD/(1 << PDRSHIFT))), %ebx
935120654Speter	shll	$PDESHIFT, %ebx
936120654Speter	addl	R(IdlePTD), %ebx
937120654Speter	orl	$(PG_V|PG_RW|PG_PS), %eax
938120654Speter1:	movl	%eax, (%ebx)
939120654Speter	addl	$(1 << PDRSHIFT), %eax
940120654Speter	addl	$PDESIZE, %ebx
941120654Speter	loop	1b
942120654Speter
943120654Speterdone_pde:
94415392Sphk/* install a pde recursively mapping page directory as a page table */
94573011Sjake	movl	R(IdlePTD), %eax
94615565Sphk	movl	$PTDPTDI, %ebx
947111372Sjake	movl	$NPGPTD,%ecx
94873011Sjake	fillkpt(R(IdlePTD), $PG_RW)
9494Srgrimes
950112841Sjake#ifdef PAE
951112841Sjake	movl	R(IdlePTD), %eax
952112841Sjake	xorl	%ebx, %ebx
953112841Sjake	movl	$NPGPTD, %ecx
954112841Sjake	fillkpt(R(IdlePDPT), $0x0)
955112841Sjake#endif
956112841Sjake
9574Srgrimes	ret
958