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