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