locore.s revision 15403
1/*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * William Jolitz.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 *	from: @(#)locore.s	7.3 (Berkeley) 5/13/91
37 *	$Id: locore.s,v 1.65 1996/04/26 13:47:37 phk Exp $
38 *
39 *		originally from: locore.s, by William F. Jolitz
40 *
41 *		Substantially rewritten by David Greenman, Rod Grimes,
42 *			Bruce Evans, Wolfgang Solfrank, Poul-Henning Kamp
43 *			and many others.
44 */
45
46#include "apm.h"
47#include "opt_ddb.h"
48
49#include <sys/errno.h>
50#include <sys/syscall.h>
51#include <sys/reboot.h>
52
53#include <machine/asmacros.h>
54#include <machine/cputypes.h>
55#include <machine/psl.h>
56#include <machine/pte.h>
57#include <machine/specialreg.h>
58
59#include "assym.s"
60
61/*
62 *	XXX
63 *
64 * Note: This version greatly munged to avoid various assembler errors
65 * that may be fixed in newer versions of gas. Perhaps newer versions
66 * will have more pleasant appearance.
67 */
68
69/*
70 * PTmap is recursive pagemap at top of virtual address space.
71 * Within PTmap, the page directory can be found (third indirection).
72 */
73	.globl	_PTmap,_PTD,_PTDpde
74	.set	_PTmap,PTDPTDI << PDRSHIFT
75	.set	_PTD,_PTmap + (PTDPTDI * NBPG)
76	.set	_PTDpde,_PTD + (PTDPTDI * PDESIZE)
77
78/*
79 * Sysmap is the base address of the kernel page tables.
80 * It is a bogus interface for kgdb and isn't used by the kernel itself.
81 */
82	.set	_Sysmap,_PTmap + (KPTDI * NBPG)
83
84/*
85 * APTmap, APTD is the alternate recursive pagemap.
86 * It's used when modifying another process's page tables.
87 */
88	.globl	_APTmap,_APTD,_APTDpde
89	.set	_APTmap,APTDPTDI << PDRSHIFT
90	.set	_APTD,_APTmap + (APTDPTDI * NBPG)
91	.set	_APTDpde,_PTD + (APTDPTDI * PDESIZE)
92
93/*
94 * Access to each processes kernel stack is via a region of
95 * per-process address space (at the beginning), immediatly above
96 * the user process stack.
97 */
98	.set	_kstack,USRSTACK
99	.globl	_kstack
100
101/*
102 * Globals
103 */
104	.data
105	ALIGN_DATA		/* just to be sure */
106
107	.globl	tmpstk
108	.space	0x2000		/* space for tmpstk - temporary stack */
109tmpstk:
110
111	.globl	_boothowto,_bootdev
112
113	.globl	_cpu,_atdevbase,_cpu_vendor,_cpu_id,_bootinfo
114	.globl	_cpu_high, _cpu_feature
115
116_cpu:	.long	0				/* are we 386, 386sx, or 486 */
117_cpu_id:	.long	0			/* stepping ID */
118_cpu_high:	.long	0			/* highest arg to CPUID */
119_cpu_feature:	.long	0			/* features */
120_cpu_vendor:	.space	20			/* CPU origin code */
121_bootinfo:	.space	BOOTINFO_SIZE		/* bootinfo that we can handle */
122_atdevbase:	.long	0			/* location of start of iomem in virtual */
123
124_KERNend:	.long	0			/* phys addr end of kernel (just after bss) */
125physfree:	.long	0			/* phys addr end of kernel (just after bss) */
126upa:	.long	0			/* phys addr end of kernel (just after bss) */
127p0s:	.long	0			/* phys addr end of kernel (just after bss) */
128
129	.globl	_IdlePTD
130_IdlePTD:	.long	0			/* phys addr of kernel PTD */
131
132_KPTphys:	.long	0			/* phys addr of kernel page tables */
133
134	.globl	_proc0paddr
135_proc0paddr:	.long	0			/* address of proc 0 address space */
136
137
138/**********************************************************************
139 *
140 * Some handy macros
141 *
142 */
143
144#define R(foo) ((foo)-KERNBASE)
145
146#define ROUND2PAGE(foo) addl $NBPG-1, foo; andl $~(NBPG-1), foo
147
148#define ALLOCPAGES(foo) \
149	movl	R(physfree), %esi ; \
150	movl	$((foo)*NBPG), %eax ; \
151	addl	%esi, %eax ; \
152	movl	%eax, R(physfree) ; \
153	movl	%esi, %edi ; \
154	movl	$((foo)*NBPG),%ecx ; \
155	xorl	%eax,%eax ; \
156	cld ; rep ; stosb
157
158/*
159 * fillkpt
160 *	eax = (page frame address | control | status) == pte
161 *	ebx = address of page table
162 *	ecx = how many pages to map
163 */
164#define	fillkpt		\
1651:	movl	%eax,(%ebx)	; \
166	addl	$NBPG,%eax	; /* increment physical address */ \
167	addl	$4,%ebx		; /* next pte */ \
168	loop	1b		;
169
170	.text
171/**********************************************************************
172 *
173 * This is where the bootblocks start us, set the ball rolling...
174 *
175 */
176NON_GPROF_ENTRY(btext)
177
178/* Tell the bios to warmboot next time */
179	movw	$0x1234,0x472
180
181/* Set up a real frame, some day we may be doing returns */
182	pushl	%ebp
183	movl	%esp, %ebp
184
185/* Don't trust what the BIOS gives for eflags. */
186	pushl	$PSL_KERNEL
187	popfl
188	mov	%ds, %ax	/* ... or segment registers */
189	mov	%ax, %es
190	mov	%ax, %fs
191	mov	%ax, %gs
192
193	call	recover_bootinfo
194
195/* get onto a stack we know the size of */
196	movl	$R(tmpstk),%esp
197	mov	%ds, %ax
198	mov	%ax, %ss
199
200	call	identify_cpu
201
202/* clear bss */
203	movl	$R(_end),%ecx
204	movl	$R(_edata),%edi
205	subl	%edi,%ecx
206	xorl	%eax,%eax
207	cld ; rep ; stosb
208
209#if NAPM > 0
210	call	_apm_setup	/* ... in i386/apm/apm_setup.s */
211#endif /* NAPM */
212
213	call	create_pagetables
214
215/* Now enable paging */
216	movl	R(_IdlePTD), %eax
217	movl	%eax,%cr3			/* load ptd addr into mmu */
218	movl	%cr0,%eax			/* get control word */
219	orl	$CR0_PE|CR0_PG,%eax		/* enable paging */
220	movl	%eax,%cr0			/* and let's page NOW! */
221
222	pushl	$begin				/* jump to high mem */
223	ret
224
225/* now running relocated at KERNBASE where the system is linked to run */
226begin:
227	/* set up bootstrap stack */
228	movl	$_kstack+UPAGES*NBPG,%esp	/* bootstrap stack end location */
229	xorl	%eax,%eax			/* mark end of frames */
230	movl	%eax,%ebp
231	movl	_proc0paddr,%eax
232	movl	_IdlePTD, %esi
233	movl	%esi,PCB_CR3(%eax)
234
235	/*
236	 * Prepare "first" - physical address of first available page
237	 * after the kernel+pdir+upages+p0stack+page tables
238	 */
239	movl	physfree, %esi
240	pushl	%esi				/* value of first for init386(first) */
241	call	_init386			/* wire 386 chip for unix operation */
242	popl	%esi
243
244	.globl	__ucodesel,__udatasel
245
246	pushl	$0				/* unused */
247	pushl	__udatasel			/* ss */
248	pushl	$0				/* esp - filled in by execve() */
249	pushl	$PSL_USER			/* eflags (IOPL 0, int enab) */
250	pushl	__ucodesel			/* cs */
251	pushl	$0				/* eip - filled in by execve() */
252	subl	$(12*4),%esp			/* space for rest of registers */
253
254	pushl	%esp				/* call main with frame pointer */
255	call	_main				/* autoconfiguration, mountroot etc */
256
257	addl	$(13*4),%esp			/* back to a frame we can return with */
258
259	/*
260	 * now we've run main() and determined what cpu-type we are, we can
261	 * enable write protection and alignment checking on i486 cpus and
262	 * above.
263	 */
264#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
265	cmpl    $CPUCLASS_386,_cpu_class
266	je	1f
267	movl	%cr0,%eax			/* get control word */
268	orl	$CR0_WP|CR0_AM,%eax		/* enable i486 features */
269	movl	%eax,%cr0			/* and do it */
270#endif
271	/*
272	 * on return from main(), we are process 1
273	 * set up address space and stack so that we can 'return' to user mode
274	 */
2751:
276	movl	__ucodesel,%eax
277	movl	__udatasel,%ecx
278
279	movl	%cx,%ds
280	movl	%cx,%es
281	movl	%ax,%fs				/* double map cs to fs */
282	movl	%cx,%gs				/* and ds to gs */
283	iret					/* goto user! */
284
285#define LCALL(x,y)	.byte 0x9a ; .long y ; .word x
286
287/*
288 * Signal trampoline, copied to top of user stack
289 */
290NON_GPROF_ENTRY(sigcode)
291	call	SIGF_HANDLER(%esp)
292	lea	SIGF_SC(%esp),%eax		/* scp (the call may have clobbered the */
293						/* copy at 8(%esp)) */
294	pushl	%eax
295	pushl	%eax				/* junk to fake return address */
296	movl	$SYS_sigreturn,%eax		/* sigreturn() */
297	LCALL(0x7,0)				/* enter kernel with args on stack */
298	hlt					/* never gets here */
299	.align	2,0x90				/* long word text-align */
300_esigcode:
301
302	.data
303	.globl	_szsigcode
304_szsigcode:
305	.long	_esigcode-_sigcode
306
307/**********************************************************************
308 *
309 * Recover the bootinfo passed to us from the boot program
310 *
311 */
312recover_bootinfo:
313	/*
314	 * This code is called in different ways depending on what loaded
315	 * and started the kernel.  This is used to detect how we get the
316	 * arguments from the other code and what we do with them.
317	 *
318	 * Old disk boot blocks:
319	 *	(*btext)(howto, bootdev, cyloffset, esym);
320	 *	[return address == 0, and can NOT be returned to]
321	 *	[cyloffset was not supported by the FreeBSD boot code
322	 *	 and always passed in as 0]
323	 *	[esym is also known as total in the boot code, and
324	 *	 was never properly supported by the FreeBSD boot code]
325	 *
326	 * Old diskless netboot code:
327	 *	(*btext)(0,0,0,0,&nfsdiskless,0,0,0);
328	 *	[return address != 0, and can NOT be returned to]
329	 *	If we are being booted by this code it will NOT work,
330	 *	so we are just going to halt if we find this case.
331	 *
332	 * New uniform boot code:
333	 *	(*btext)(howto, bootdev, 0, 0, 0, &bootinfo)
334	 *	[return address != 0, and can be returned to]
335	 *
336	 * There may seem to be a lot of wasted arguments in here, but
337	 * that is so the newer boot code can still load very old kernels
338	 * and old boot code can load new kernels.
339	 */
340
341	/*
342	 * The old style disk boot blocks fake a frame on the stack and
343	 * did an lret to get here.  The frame on the stack has a return
344	 * address of 0.
345	 */
346	cmpl	$0,4(%ebp)
347	je	olddiskboot
348
349	/*
350	 * We have some form of return address, so this is either the
351	 * old diskless netboot code, or the new uniform code.  That can
352	 * be detected by looking at the 5th argument, it if is 0 we
353	 * we are being booted by the new unifrom boot code.
354	 */
355	cmpl	$0,24(%ebp)
356	je	newboot
357
358	/*
359	 * Seems we have been loaded by the old diskless boot code, we
360	 * don't stand a chance of running as the diskless structure
361	 * changed considerably between the two, so just halt.
362	 */
363	 hlt
364
365	/*
366	 * We have been loaded by the new uniform boot code.
367	 * Lets check the bootinfo version, and if we do not understand
368	 * it we return to the loader with a status of 1 to indicate this error
369	 */
370newboot:
371	movl	28(%ebp),%ebx		/* &bootinfo.version */
372	movl	BI_VERSION(%ebx),%eax
373	cmpl	$1,%eax			/* We only understand version 1 */
374	je	1f
375	movl	$1,%eax			/* Return status */
376	add	$4, %esp		/* pop recover_bootinfo's retaddr */
377	leave
378	ret
379
3801:
381	/*
382	 * If we have a kernelname copy it in
383	 */
384	movl	BI_KERNELNAME(%ebx),%esi
385	cmpl	$0,%esi
386	je	2f			/* No kernelname */
387	movl	$MAXPATHLEN,%ecx	/* Brute force!!! */
388	lea	_kernelname-KERNBASE,%edi
389	cmpb	$'/',(%esi)		/* Make sure it starts with a slash */
390	je	1f
391	movb	$'/',(%edi)
392	incl	%edi
393	decl	%ecx
3941:
395	cld
396	rep
397	movsb
398
3992:
400	/*
401	 * Determine the size of the boot loader's copy of the bootinfo
402	 * struct.  This is impossible to do properly because old versions
403	 * of the struct don't contain a size field and there are 2 old
404	 * versions with the same version number.
405	 */
406	movl	$BI_ENDCOMMON,%ecx	/* prepare for sizeless version */
407	testl	$RB_BOOTINFO,8(%ebp)	/* bi_size (and bootinfo) valid? */
408	je	got_bi_size		/* no, sizeless version */
409	movl	BI_SIZE(%ebx),%ecx
410got_bi_size:
411
412	/*
413	 * Copy the common part of the bootinfo struct
414	 */
415	movl	%ebx,%esi
416	movl	$_bootinfo-KERNBASE,%edi
417	cmpl	$BOOTINFO_SIZE,%ecx
418	jbe	got_common_bi_size
419	movl	$BOOTINFO_SIZE,%ecx
420got_common_bi_size:
421	cld
422	rep
423	movsb
424
425#ifdef NFS
426	/*
427	 * If we have a nfs_diskless structure copy it in
428	 */
429	movl	BI_NFS_DISKLESS(%ebx),%esi
430	cmpl	$0,%esi
431	je	2f
432	lea	_nfs_diskless-KERNBASE,%edi
433	movl	$NFSDISKLESS_SIZE,%ecx
434	cld
435	rep
436	movsb
437	lea	_nfs_diskless_valid-KERNBASE,%edi
438	movl	$1,(%edi)
439#endif
440
441	/*
442	 * The old style disk boot.
443	 *	(*btext)(howto, bootdev, cyloffset, esym);
444	 * Note that the newer boot code just falls into here to pick
445	 * up howto and bootdev, cyloffset and esym are no longer used
446	 */
447olddiskboot:
448	movl	8(%ebp),%eax
449	movl	%eax,_boothowto-KERNBASE
450	movl	12(%ebp),%eax
451	movl	%eax,_bootdev-KERNBASE
452
453	ret
454
455
456/**********************************************************************
457 *
458 * Identify the CPU and initialize anything special about it
459 *
460 */
461identify_cpu:
462
463	/* Try to toggle alignment check flag; does not exist on 386. */
464	pushfl
465	popl	%eax
466	movl	%eax,%ecx
467	orl	$PSL_AC,%eax
468	pushl	%eax
469	popfl
470	pushfl
471	popl	%eax
472	xorl	%ecx,%eax
473	andl	$PSL_AC,%eax
474	pushl	%ecx
475	popfl
476
477	testl	%eax,%eax
478	jnz	1f
479	movl	$CPU_386,_cpu-KERNBASE
480	jmp	3f
481
4821:	/* Try to toggle identification flag; does not exist on early 486s. */
483	pushfl
484	popl	%eax
485	movl	%eax,%ecx
486	xorl	$PSL_ID,%eax
487	pushl	%eax
488	popfl
489	pushfl
490	popl	%eax
491	xorl	%ecx,%eax
492	andl	$PSL_ID,%eax
493	pushl	%ecx
494	popfl
495
496	testl	%eax,%eax
497	jnz	1f
498	movl	$CPU_486,_cpu-KERNBASE
499
500	/* check for Cyrix 486DLC -- based on check routine  */
501	/* documented in "Cx486SLC/e SMM Programmer's Guide" */
502	xorw	%dx,%dx
503	cmpw	%dx,%dx			# set flags to known state
504	pushfw
505	popw	%cx			# store flags in ecx
506	movw	$0xffff,%ax
507	movw	$0x0004,%bx
508	divw	%bx
509	pushfw
510	popw	%ax
511	andw	$0x08d5,%ax		# mask off important bits
512	andw	$0x08d5,%cx
513	cmpw	%ax,%cx
514
515	jnz	3f			# if flags changed, Intel chip
516
517	movl	$CPU_486DLC,_cpu-KERNBASE # set CPU value for Cyrix
518	movl	$0x69727943,_cpu_vendor-KERNBASE	# store vendor string
519	movw	$0x0078,_cpu_vendor-KERNBASE+4
520
521#ifndef CYRIX_CACHE_WORKS
522	/* Disable caching of the ISA hole only. */
523	invd
524	movb	$CCR0,%al		# Configuration Register index (CCR0)
525	outb	%al,$0x22
526	inb	$0x23,%al
527	orb	$(CCR0_NC1|CCR0_BARB),%al
528	movb	%al,%ah
529	movb	$CCR0,%al
530	outb	%al,$0x22
531	movb	%ah,%al
532	outb	%al,$0x23
533	invd
534#else /* CYRIX_CACHE_WORKS */
535	/* Set cache parameters */
536	invd				# Start with guaranteed clean cache
537	movb	$CCR0,%al		# Configuration Register index (CCR0)
538	outb	%al,$0x22
539	inb	$0x23,%al
540	andb	$~CCR0_NC0,%al
541#ifndef CYRIX_CACHE_REALLY_WORKS
542	orb	$(CCR0_NC1|CCR0_BARB),%al
543#else /* !CYRIX_CACHE_REALLY_WORKS */
544	orb	$CCR0_NC1,%al
545#endif /* CYRIX_CACHE_REALLY_WORKS */
546	movb	%al,%ah
547	movb	$CCR0,%al
548	outb	%al,$0x22
549	movb	%ah,%al
550	outb	%al,$0x23
551	/* clear non-cacheable region 1	*/
552	movb	$(NCR1+2),%al
553	outb	%al,$0x22
554	movb	$NCR_SIZE_0K,%al
555	outb	%al,$0x23
556	/* clear non-cacheable region 2	*/
557	movb	$(NCR2+2),%al
558	outb	%al,$0x22
559	movb	$NCR_SIZE_0K,%al
560	outb	%al,$0x23
561	/* clear non-cacheable region 3	*/
562	movb	$(NCR3+2),%al
563	outb	%al,$0x22
564	movb	$NCR_SIZE_0K,%al
565	outb	%al,$0x23
566	/* clear non-cacheable region 4	*/
567	movb	$(NCR4+2),%al
568	outb	%al,$0x22
569	movb	$NCR_SIZE_0K,%al
570	outb	%al,$0x23
571	/* enable caching in CR0 */
572	movl	%cr0,%eax
573	andl	$~(CR0_CD|CR0_NW),%eax
574	movl	%eax,%cr0
575	invd
576#endif /* CYRIX_CACHE_WORKS */
577	jmp	3f
578
5791:	/* Use the `cpuid' instruction. */
580	xorl	%eax,%eax
581	.byte	0x0f,0xa2			# cpuid 0
582	movl	%eax,_cpu_high-KERNBASE		# highest capability
583	movl	%ebx,_cpu_vendor-KERNBASE	# store vendor string
584	movl	%edx,_cpu_vendor+4-KERNBASE
585	movl	%ecx,_cpu_vendor+8-KERNBASE
586	movb	$0,_cpu_vendor+12-KERNBASE
587
588	movl	$1,%eax
589	.byte	0x0f,0xa2			# cpuid 1
590	movl	%eax,_cpu_id-KERNBASE		# store cpu_id
591	movl	%edx,_cpu_feature-KERNBASE	# store cpu_feature
592	rorl	$8,%eax				# extract family type
593	andl	$15,%eax
594	cmpl	$5,%eax
595	jae	1f
596
597	/* less than Pentium; must be 486 */
598	movl	$CPU_486,_cpu-KERNBASE
599	jmp	3f
6001:
601	/* a Pentium? */
602	cmpl	$5,%eax
603	jne	2f
604	movl	$CPU_586,_cpu-KERNBASE
605	jmp	3f
6062:
607	/* Greater than Pentium...call it a Pentium Pro */
608	movl	$CPU_686,_cpu-KERNBASE
6093:
610	ret
611
612
613/**********************************************************************
614 *
615 * Create the first page directory and it's page tables
616 *
617 */
618
619create_pagetables:
620
621/* find end of kernel image */
622	movl	$R(_end),%esi
623
624/* include symbols in "kernel image" if they are loaded and useful */
625#ifdef DDB
626	movl	R(_bootinfo+BI_ESYMTAB),%edi
627	testl	%edi,%edi
628	je	1f
629	movl	%edi,%esi
630	movl	$KERNBASE,%edi
631	addl	%edi,R(_bootinfo+BI_SYMTAB)
632	addl	%edi,R(_bootinfo+BI_ESYMTAB)
6331:
634#endif
635
636	ROUND2PAGE(%esi)
637	movl	%esi,R(_KERNend)	/* save end of kernel */
638	movl	%esi,R(physfree)	/* save end of kernel */
639
640/* Allocate Kernel Page Tables */
641	ALLOCPAGES(NKPT)
642	movl	%esi,R(_KPTphys)
643
644/* Allocate Page Table Directory */
645	ALLOCPAGES(1)
646	movl	%esi,R(_IdlePTD)
647
648/* Allocate UPAGES */
649	ALLOCPAGES(UPAGES)
650	movl	%esi,R(upa);
651	addl	$KERNBASE, %esi
652	movl	%esi, R(_proc0paddr)
653
654/* Allocate P0 Stack */
655	ALLOCPAGES(1)
656	movl	%esi,R(p0s);
657
658/* Map read-only from zero to the end of the kernel text section */
659	movl	R(_KPTphys), %esi
660	movl	$R(_etext),%ecx
661	addl	$NBPG-1,%ecx
662	shrl	$PGSHIFT,%ecx
663	movl	$PG_V|PG_KR,%eax
664	movl	%esi, %ebx
665	fillkpt
666
667/* Map read-write, data, bss and symbols */
668	andl	$PG_FRAME,%eax
669	movl	R(_KERNend),%ecx
670	subl	%eax,%ecx
671	shrl	$PGSHIFT,%ecx
672	orl	$PG_V|PG_KW,%eax
673	fillkpt
674
675/* Map PD */
676	movl	R(_IdlePTD), %eax
677	movl	$1, %ecx
678	movl	%eax, %ebx
679	shrl	$PGSHIFT-2, %ebx
680	addl	R(_KPTphys), %ebx
681	orl	$PG_V|PG_KW, %eax
682	fillkpt
683
684/* Map Proc 0 kernel stack */
685	movl	R(p0s), %eax
686	movl	$1, %ecx
687	movl	%eax, %ebx
688	shrl	$PGSHIFT-2, %ebx
689	addl	R(_KPTphys), %ebx
690	orl	$PG_V|PG_KW, %eax
691	fillkpt
692
693/* ... also in user page table page */
694	movl	R(p0s), %eax
695	movl	$1, %ecx
696	orl	$PG_V|PG_KW, %eax
697	movl	R(_KPTphys), %ebx
698	addl	$(KSTKPTEOFF * PTESIZE), %ebx
699	fillkpt
700
701/* Map UPAGES */
702	movl	R(upa), %eax
703	movl	$UPAGES, %ecx
704	movl	%eax, %ebx
705	shrl	$PGSHIFT-2, %ebx
706	addl	R(_KPTphys), %ebx
707	orl	$PG_V|PG_KW, %eax
708	fillkpt
709
710/* ... also in user page table page */
711	movl	R(upa), %eax
712	movl	$UPAGES, %ecx
713	orl	$PG_V|PG_KW, %eax
714	movl	R(p0s), %ebx
715	addl	$(KSTKPTEOFF * PTESIZE), %ebx
716	fillkpt
717
718/* and a pde entry too */
719	movl	R(p0s), %eax
720	movl	R(_IdlePTD), %esi
721	orl	$PG_V|PG_KW,%eax
722	movl	%eax,KSTKPTDI*PDESIZE(%esi)
723
724/* Map ISA hole */
725#define ISA_HOLE_START	  0xa0000
726#define ISA_HOLE_LENGTH (0x100000-ISA_HOLE_START)
727	movl	$ISA_HOLE_LENGTH>>PGSHIFT, %ecx
728	movl	$ISA_HOLE_START, %eax
729	movl	%eax, %ebx
730	shrl	$PGSHIFT-2, %ebx
731	addl	R(_KPTphys), %ebx
732	orl	$PG_V|PG_KW|PG_N, %eax
733	fillkpt
734	movl	$ISA_HOLE_START, %eax
735	addl	$KERNBASE, %eax
736	movl	%eax, R(_atdevbase)
737
738/* install a pde for temporary double map of bottom of VA */
739	movl	R(_IdlePTD), %esi
740	movl	R(_KPTphys), %eax
741	orl     $PG_V|PG_KW, %eax
742	movl	%eax, (%esi)
743
744/* install pde's for pt's */
745	movl	R(_IdlePTD), %esi
746	movl	R(_KPTphys), %eax
747	orl     $PG_V|PG_KW, %eax
748	movl	$(NKPT), %ecx
749	lea	(KPTDI*PDESIZE)(%esi), %ebx
750	fillkpt
751
752/* install a pde recursively mapping page directory as a page table */
753	movl	R(_IdlePTD), %esi
754	movl	%esi,%eax
755	orl	$PG_V|PG_KW,%eax
756	movl	%eax,PTDPTDI*PDESIZE(%esi)
757
758	ret
759