xref: /freebsd/sys/i386/i386/locore.S (revision 9768746b)
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 */
82ENTRY(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	 *	This code from 1.x/2.x doesn't supply now-required metadata and
182	 *	likely will fail (we test for it to avoid dereferencing stack
183	 *	garbage here).
184	 *
185	 * Old diskless netboot code:
186	 *	(*btext)(0,0,0,0,&nfsdiskless,0,0,0);
187	 *	[return address != 0, and can NOT be returned to]
188	 *	If we are being booted by this code it will NOT work,
189	 *	so we are just going to halt if we find this case.
190	 *
191	 * New uniform boot code:
192	 *	(*btext)(howto, bootdev, 0, 0, 0, &bootinfo)
193	 *	[return address != 0, and can be returned to]
194	 *
195	 * There may seem to be a lot of wasted arguments in here, but
196	 * that is so the newer boot code can still load very old kernels
197	 * and old boot code can load new kernels.
198	 */
199
200	/*
201	 * The old style disk boot blocks fake a frame on the stack and did an
202	 * lret to get here.  The frame on the stack has a return address of 0.
203	 * This style of boot (from 1.x / 2.x) almost certainly won't work,
204	 * since the kernel has required metadata since about 7.x or so and none
205	 * are present.
206	 */
207	cmpl	$0,4(%ebp)
208	je	olddiskboot
209
210	/*
211	 * We have some form of return address, so this is either the
212	 * old diskless netboot code, or the new uniform code.  That can
213	 * be detected by looking at the 5th argument, if it is 0
214	 * we are being booted by the new uniform boot code.
215	 */
216	cmpl	$0,24(%ebp)
217	je	newboot
218
219	/*
220	 * Seems we have been loaded by the old 1.x/2.x diskless boot code, we
221	 * don't stand a chance of running as the diskless structure changed
222	 * considerably between the two, so just halt.
223	 */
224	 hlt
225
226	/*
227	 * We have been loaded by the new uniform boot code.
228	 * Let's check the bootinfo version, and if we do not understand
229	 * it we return to the loader with a status of 1 to indicate this error
230	 */
231newboot:
232	movl	28(%ebp),%ebx		/* &bootinfo.version */
233	movl	BI_VERSION(%ebx),%eax
234	cmpl	$1,%eax			/* We only understand version 1 */
235	je	1f
236	testl   $RB_BOOTINFO,8(%ebp)    /* bi_size (and bootinfo) valid? */
237	jne	1f
238	movl	$1,%eax			/* Return status */
239	leave
240	/*
241	 * XXX this returns to our caller's caller (as is required) since
242	 * we didn't set up a frame and our caller did.
243	 */
244	ret
245
2461:
247	/*
248	 * If we have a kernelname copy it in
249	 */
250	movl	BI_KERNELNAME(%ebx),%esi
251	cmpl	$0,%esi
252	je	2f			/* No kernelname */
253	movl	$MAXPATHLEN,%ecx	/* Brute force!!! */
254	movl	$kernelname,%edi
255	cmpb	$'/',(%esi)		/* Make sure it starts with a slash */
256	je	1f
257	movb	$'/',(%edi)
258	incl	%edi
259	decl	%ecx
2601:
261	cld
262	rep
263	movsb
264
2652:
266	/*
267	 * Determine the size of the boot loader's copy of the bootinfo
268	 * struct. Copy min(our size, loader's size) into our bootinfo.
269	 * Incompatible with really old boot loaders from FreeBSD 1.x and 2.0.
270	 */
271	movl	%ebx,%esi
272	movl	$bootinfo,%edi
273	movl	BI_SIZE(%ebx),%ecx
274	cmpl	$BOOTINFO_SIZE,%ecx
275	jbe	got_common_bi_size
276	movl	$BOOTINFO_SIZE,%ecx
277got_common_bi_size:
278	cld
279	rep
280	movsb
281
282#ifdef NFS_ROOT
283#ifndef BOOTP_NFSV3
284	/*
285	 * If we have a nfs_diskless structure copy it in
286	 */
287	movl	BI_NFS_DISKLESS(%ebx),%esi
288	cmpl	$0,%esi
289	je	olddiskboot
290	movl	$nfs_diskless,%edi
291	movl	$NFSDISKLESS_SIZE,%ecx
292	cld
293	rep
294	movsb
295	movl	$nfs_diskless_valid,%edi
296	movl	$1,(%edi)
297#endif
298#endif
299
300	/*
301	 * The old style disk boot.
302	 *	(*btext)(howto, bootdev, cyloffset, esym);
303	 * Note that the newer boot code just falls into here to pick
304	 * up howto and bootdev, cyloffset and esym are no longer used
305	 */
306olddiskboot:
307	movl	8(%ebp),%eax
308	movl	%eax,boothowto
309	movl	12(%ebp),%eax
310	movl	%eax,bootdev
311
312	ret
313
314
315/**********************************************************************
316 *
317 * Identify the CPU and initialize anything special about it
318 *
319 */
320ENTRY(identify_cpu)
321
322	pushl	%ebx
323
324	/* Try to toggle alignment check flag; does not exist on 386. */
325	pushfl
326	popl	%eax
327	movl	%eax,%ecx
328	orl	$PSL_AC,%eax
329	pushl	%eax
330	popfl
331	pushfl
332	popl	%eax
333	xorl	%ecx,%eax
334	andl	$PSL_AC,%eax
335	pushl	%ecx
336	popfl
337
338	testl	%eax,%eax
339	jnz	try486
340
341	/* NexGen CPU does not have alignment check flag. */
342	pushfl
343	movl	$0x5555, %eax
344	xorl	%edx, %edx
345	movl	$2, %ecx
346	clc
347	divl	%ecx
348	jz	trynexgen
349	popfl
350	movl	$CPU_386,cpu
351	jmp	3f
352
353trynexgen:
354	popfl
355	movl	$CPU_NX586,cpu
356	movl	$0x4778654e,cpu_vendor		# store vendor string
357	movl	$0x72446e65,cpu_vendor+4
358	movl	$0x6e657669,cpu_vendor+8
359	movl	$0,cpu_vendor+12
360	jmp	3f
361
362try486:	/* Try to toggle identification flag; does not exist on early 486s. */
363	pushfl
364	popl	%eax
365	movl	%eax,%ecx
366	xorl	$PSL_ID,%eax
367	pushl	%eax
368	popfl
369	pushfl
370	popl	%eax
371	xorl	%ecx,%eax
372	andl	$PSL_ID,%eax
373	pushl	%ecx
374	popfl
375
376	testl	%eax,%eax
377	jnz	trycpuid
378	movl	$CPU_486,cpu
379
380	/*
381	 * Check Cyrix CPU
382	 * Cyrix CPUs do not change the undefined flags following
383	 * execution of the divide instruction which divides 5 by 2.
384	 *
385	 * Note: CPUID is enabled on M2, so it passes another way.
386	 */
387	pushfl
388	movl	$0x5555, %eax
389	xorl	%edx, %edx
390	movl	$2, %ecx
391	clc
392	divl	%ecx
393	jnc	trycyrix
394	popfl
395	jmp	3f		/* You may use Intel CPU. */
396
397trycyrix:
398	popfl
399	/*
400	 * IBM Bluelighting CPU also doesn't change the undefined flags.
401	 * Because IBM doesn't disclose the information for Bluelighting
402	 * CPU, we couldn't distinguish it from Cyrix's (including IBM
403	 * brand of Cyrix CPUs).
404	 */
405	movl	$0x69727943,cpu_vendor		# store vendor string
406	movl	$0x736e4978,cpu_vendor+4
407	movl	$0x64616574,cpu_vendor+8
408	jmp	3f
409
410trycpuid:	/* Use the `cpuid' instruction. */
411	xorl	%eax,%eax
412	cpuid					# cpuid 0
413	movl	%eax,cpu_high			# highest capability
414	movl	%ebx,cpu_vendor			# store vendor string
415	movl	%edx,cpu_vendor+4
416	movl	%ecx,cpu_vendor+8
417	movb	$0,cpu_vendor+12
418
419	movl	$1,%eax
420	cpuid					# cpuid 1
421	movl	%eax,cpu_id			# store cpu_id
422	movl	%ebx,cpu_procinfo		# store cpu_procinfo
423	movl	%edx,cpu_feature		# store cpu_feature
424	movl	%ecx,cpu_feature2		# store cpu_feature2
425	rorl	$8,%eax				# extract family type
426	andl	$15,%eax
427	cmpl	$5,%eax
428	jae	1f
429
430	/* less than Pentium; must be 486 */
431	movl	$CPU_486,cpu
432	jmp	3f
4331:
434	/* a Pentium? */
435	cmpl	$5,%eax
436	jne	2f
437	movl	$CPU_586,cpu
438	jmp	3f
4392:
440	/* Greater than Pentium...call it a Pentium Pro */
441	movl	$CPU_686,cpu
4423:
443	popl	%ebx
444	ret
445END(identify_cpu)
446
447#ifdef XENHVM
448/* Xen Hypercall page */
449	.text
450.p2align PAGE_SHIFT, 0x90	/* Hypercall_page needs to be PAGE aligned */
451
452ENTRY(hypercall_page)
453	.skip	0x1000, 0x90	/* Fill with "nop"s */
454#endif
455