xref: /f-stack/freebsd/i386/i386/locore.s (revision 22ce4aff)
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. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 *	from: @(#)locore.s	7.3 (Berkeley) 5/13/91
33 * $FreeBSD$
34 *
35 *		originally from: locore.s, by William F. Jolitz
36 *
37 *		Substantially rewritten by David Greenman, Rod Grimes,
38 *			Bruce Evans, Wolfgang Solfrank, Poul-Henning Kamp
39 *			and many others.
40 */
41
42#include "opt_bootp.h"
43#include "opt_nfsroot.h"
44#include "opt_pmap.h"
45
46#include <sys/reboot.h>
47
48#include <machine/asmacros.h>
49#include <machine/cputypes.h>
50#include <machine/psl.h>
51#include <machine/pmap.h>
52#include <machine/specialreg.h>
53
54#include "assym.inc"
55
56/*
57 * Compiled KERNBASE location and the kernel load address, now identical.
58 */
59	.globl	kernbase
60	.set	kernbase,KERNBASE
61	.globl	kernload
62	.set	kernload,KERNLOAD
63
64/*
65 * Globals
66 */
67	.data
68	ALIGN_DATA			/* just to be sure */
69
70	.space	0x2000			/* space for tmpstk - temporary stack */
71tmpstk:
72
73	.globl	bootinfo
74bootinfo:	.space	BOOTINFO_SIZE	/* bootinfo that we can handle */
75
76	.text
77/**********************************************************************
78 *
79 * This is where the bootblocks start us, set the ball rolling...
80 *
81 */
82NON_GPROF_ENTRY(btext)
83
84/* Tell the bios to warmboot next time */
85	movw	$0x1234,0x472
86
87/* Set up a real frame in case the double return in newboot is executed. */
88	xorl	%ebp,%ebp
89	pushl	%ebp
90	movl	%esp, %ebp
91
92/* Don't trust what the BIOS gives for eflags. */
93	pushl	$PSL_KERNEL
94	popfl
95
96/*
97 * Don't trust what the BIOS gives for %fs and %gs.  Trust the bootstrap
98 * to set %cs, %ds, %es and %ss.
99 */
100	mov	%ds, %ax
101	mov	%ax, %fs
102	mov	%ax, %gs
103
104/*
105 * Clear the bss.  Not all boot programs do it, and it is our job anyway.
106 *
107 * XXX we don't check that there is memory for our bss and page tables
108 * before using it.
109 *
110 * Note: we must be careful to not overwrite an active gdt or idt.  They
111 * inactive from now until we switch to new ones, since we don't load any
112 * more segment registers or permit interrupts until after the switch.
113 */
114	movl	$__bss_end,%ecx
115	movl	$__bss_start,%edi
116	subl	%edi,%ecx
117	xorl	%eax,%eax
118	cld
119	rep
120	stosb
121
122	call	recover_bootinfo
123
124/* Get onto a stack that we can trust. */
125/*
126 * XXX this step is delayed in case recover_bootinfo needs to return via
127 * the old stack, but it need not be, since recover_bootinfo actually
128 * returns via the old frame.
129 */
130	movl	$tmpstk,%esp
131
132	call	identify_cpu
133	call	pmap_cold
134
135	/* set up bootstrap stack */
136	movl	proc0kstack,%eax	/* location of in-kernel stack */
137
138	/*
139	 * Only use bottom page for init386().  init386() calculates the
140	 * PCB + FPU save area size and returns the true top of stack.
141	 */
142	leal	PAGE_SIZE(%eax),%esp
143
144	xorl	%ebp,%ebp		/* mark end of frames */
145
146	pushl	physfree		/* value of first for init386(first) */
147	call	init386			/* wire 386 chip for unix operation */
148
149	/*
150	 * Clean up the stack in a way that db_numargs() understands, so
151	 * that backtraces in ddb don't underrun the stack.  Traps for
152	 * inaccessible memory are more fatal than usual this early.
153	 */
154	addl	$4,%esp
155
156	/* Switch to true top of stack. */
157	movl	%eax,%esp
158
159	call	mi_startup		/* autoconfiguration, mountroot etc */
160	/* NOTREACHED */
161	addl	$0,%esp			/* for db_numargs() again */
162
163/**********************************************************************
164 *
165 * Recover the bootinfo passed to us from the boot program
166 *
167 */
168recover_bootinfo:
169	/*
170	 * This code is called in different ways depending on what loaded
171	 * and started the kernel.  This is used to detect how we get the
172	 * arguments from the other code and what we do with them.
173	 *
174	 * Old disk boot blocks:
175	 *	(*btext)(howto, bootdev, cyloffset, esym);
176	 *	[return address == 0, and can NOT be returned to]
177	 *	[cyloffset was not supported by the FreeBSD boot code
178	 *	 and always passed in as 0]
179	 *	[esym is also known as total in the boot code, and
180	 *	 was never properly supported by the FreeBSD boot code]
181	 *
182	 * Old diskless netboot code:
183	 *	(*btext)(0,0,0,0,&nfsdiskless,0,0,0);
184	 *	[return address != 0, and can NOT be returned to]
185	 *	If we are being booted by this code it will NOT work,
186	 *	so we are just going to halt if we find this case.
187	 *
188	 * New uniform boot code:
189	 *	(*btext)(howto, bootdev, 0, 0, 0, &bootinfo)
190	 *	[return address != 0, and can be returned to]
191	 *
192	 * There may seem to be a lot of wasted arguments in here, but
193	 * that is so the newer boot code can still load very old kernels
194	 * and old boot code can load new kernels.
195	 */
196
197	/*
198	 * The old style disk boot blocks fake a frame on the stack and
199	 * did an lret to get here.  The frame on the stack has a return
200	 * address of 0.
201	 */
202	cmpl	$0,4(%ebp)
203	je	olddiskboot
204
205	/*
206	 * We have some form of return address, so this is either the
207	 * old diskless netboot code, or the new uniform code.  That can
208	 * be detected by looking at the 5th argument, if it is 0
209	 * we are being booted by the new uniform boot code.
210	 */
211	cmpl	$0,24(%ebp)
212	je	newboot
213
214	/*
215	 * Seems we have been loaded by the old diskless boot code, we
216	 * don't stand a chance of running as the diskless structure
217	 * changed considerably between the two, so just halt.
218	 */
219	 hlt
220
221	/*
222	 * We have been loaded by the new uniform boot code.
223	 * Let's check the bootinfo version, and if we do not understand
224	 * it we return to the loader with a status of 1 to indicate this error
225	 */
226newboot:
227	movl	28(%ebp),%ebx		/* &bootinfo.version */
228	movl	BI_VERSION(%ebx),%eax
229	cmpl	$1,%eax			/* We only understand version 1 */
230	je	1f
231	movl	$1,%eax			/* Return status */
232	leave
233	/*
234	 * XXX this returns to our caller's caller (as is required) since
235	 * we didn't set up a frame and our caller did.
236	 */
237	ret
238
2391:
240	/*
241	 * If we have a kernelname copy it in
242	 */
243	movl	BI_KERNELNAME(%ebx),%esi
244	cmpl	$0,%esi
245	je	2f			/* No kernelname */
246	movl	$MAXPATHLEN,%ecx	/* Brute force!!! */
247	movl	$kernelname,%edi
248	cmpb	$'/',(%esi)		/* Make sure it starts with a slash */
249	je	1f
250	movb	$'/',(%edi)
251	incl	%edi
252	decl	%ecx
2531:
254	cld
255	rep
256	movsb
257
2582:
259	/*
260	 * Determine the size of the boot loader's copy of the bootinfo
261	 * struct.  This is impossible to do properly because old versions
262	 * of the struct don't contain a size field and there are 2 old
263	 * versions with the same version number.
264	 */
265	movl	$BI_ENDCOMMON,%ecx	/* prepare for sizeless version */
266	testl	$RB_BOOTINFO,8(%ebp)	/* bi_size (and bootinfo) valid? */
267	je	got_bi_size		/* no, sizeless version */
268	movl	BI_SIZE(%ebx),%ecx
269got_bi_size:
270
271	/*
272	 * Copy the common part of the bootinfo struct
273	 */
274	movl	%ebx,%esi
275	movl	$bootinfo,%edi
276	cmpl	$BOOTINFO_SIZE,%ecx
277	jbe	got_common_bi_size
278	movl	$BOOTINFO_SIZE,%ecx
279got_common_bi_size:
280	cld
281	rep
282	movsb
283
284#ifdef NFS_ROOT
285#ifndef BOOTP_NFSV3
286	/*
287	 * If we have a nfs_diskless structure copy it in
288	 */
289	movl	BI_NFS_DISKLESS(%ebx),%esi
290	cmpl	$0,%esi
291	je	olddiskboot
292	movl	$nfs_diskless,%edi
293	movl	$NFSDISKLESS_SIZE,%ecx
294	cld
295	rep
296	movsb
297	movl	$nfs_diskless_valid,%edi
298	movl	$1,(%edi)
299#endif
300#endif
301
302	/*
303	 * The old style disk boot.
304	 *	(*btext)(howto, bootdev, cyloffset, esym);
305	 * Note that the newer boot code just falls into here to pick
306	 * up howto and bootdev, cyloffset and esym are no longer used
307	 */
308olddiskboot:
309	movl	8(%ebp),%eax
310	movl	%eax,boothowto
311	movl	12(%ebp),%eax
312	movl	%eax,bootdev
313
314	ret
315
316
317/**********************************************************************
318 *
319 * Identify the CPU and initialize anything special about it
320 *
321 */
322ENTRY(identify_cpu)
323
324	pushl	%ebx
325
326	/* Try to toggle alignment check flag; does not exist on 386. */
327	pushfl
328	popl	%eax
329	movl	%eax,%ecx
330	orl	$PSL_AC,%eax
331	pushl	%eax
332	popfl
333	pushfl
334	popl	%eax
335	xorl	%ecx,%eax
336	andl	$PSL_AC,%eax
337	pushl	%ecx
338	popfl
339
340	testl	%eax,%eax
341	jnz	try486
342
343	/* NexGen CPU does not have aligment check flag. */
344	pushfl
345	movl	$0x5555, %eax
346	xorl	%edx, %edx
347	movl	$2, %ecx
348	clc
349	divl	%ecx
350	jz	trynexgen
351	popfl
352	movl	$CPU_386,cpu
353	jmp	3f
354
355trynexgen:
356	popfl
357	movl	$CPU_NX586,cpu
358	movl	$0x4778654e,cpu_vendor		# store vendor string
359	movl	$0x72446e65,cpu_vendor+4
360	movl	$0x6e657669,cpu_vendor+8
361	movl	$0,cpu_vendor+12
362	jmp	3f
363
364try486:	/* Try to toggle identification flag; does not exist on early 486s. */
365	pushfl
366	popl	%eax
367	movl	%eax,%ecx
368	xorl	$PSL_ID,%eax
369	pushl	%eax
370	popfl
371	pushfl
372	popl	%eax
373	xorl	%ecx,%eax
374	andl	$PSL_ID,%eax
375	pushl	%ecx
376	popfl
377
378	testl	%eax,%eax
379	jnz	trycpuid
380	movl	$CPU_486,cpu
381
382	/*
383	 * Check Cyrix CPU
384	 * Cyrix CPUs do not change the undefined flags following
385	 * execution of the divide instruction which divides 5 by 2.
386	 *
387	 * Note: CPUID is enabled on M2, so it passes another way.
388	 */
389	pushfl
390	movl	$0x5555, %eax
391	xorl	%edx, %edx
392	movl	$2, %ecx
393	clc
394	divl	%ecx
395	jnc	trycyrix
396	popfl
397	jmp	3f		/* You may use Intel CPU. */
398
399trycyrix:
400	popfl
401	/*
402	 * IBM Bluelighting CPU also doesn't change the undefined flags.
403	 * Because IBM doesn't disclose the information for Bluelighting
404	 * CPU, we couldn't distinguish it from Cyrix's (including IBM
405	 * brand of Cyrix CPUs).
406	 */
407	movl	$0x69727943,cpu_vendor		# store vendor string
408	movl	$0x736e4978,cpu_vendor+4
409	movl	$0x64616574,cpu_vendor+8
410	jmp	3f
411
412trycpuid:	/* Use the `cpuid' instruction. */
413	xorl	%eax,%eax
414	cpuid					# cpuid 0
415	movl	%eax,cpu_high			# highest capability
416	movl	%ebx,cpu_vendor			# store vendor string
417	movl	%edx,cpu_vendor+4
418	movl	%ecx,cpu_vendor+8
419	movb	$0,cpu_vendor+12
420
421	movl	$1,%eax
422	cpuid					# cpuid 1
423	movl	%eax,cpu_id			# store cpu_id
424	movl	%ebx,cpu_procinfo		# store cpu_procinfo
425	movl	%edx,cpu_feature		# store cpu_feature
426	movl	%ecx,cpu_feature2		# store cpu_feature2
427	rorl	$8,%eax				# extract family type
428	andl	$15,%eax
429	cmpl	$5,%eax
430	jae	1f
431
432	/* less than Pentium; must be 486 */
433	movl	$CPU_486,cpu
434	jmp	3f
4351:
436	/* a Pentium? */
437	cmpl	$5,%eax
438	jne	2f
439	movl	$CPU_586,cpu
440	jmp	3f
4412:
442	/* Greater than Pentium...call it a Pentium Pro */
443	movl	$CPU_686,cpu
4443:
445	popl	%ebx
446	ret
447END(identify_cpu)
448
449#ifdef XENHVM
450/* Xen Hypercall page */
451	.text
452.p2align PAGE_SHIFT, 0x90	/* Hypercall_page needs to be PAGE aligned */
453
454NON_GPROF_ENTRY(hypercall_page)
455	.skip	0x1000, 0x90	/* Fill with "nop"s */
456#endif
457