xref: /titanic_50/usr/src/uts/i86pc/dboot/dboot_grub.s (revision 753a6d457b330b1b29b2d3eefcd0831116ce950d)
1
2/*
3 * CDDL HEADER START
4 *
5 * The contents of this file are subject to the terms of the
6 * Common Development and Distribution License (the "License").
7 * You may not use this file except in compliance with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22
23/*
24 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
25 * Use is subject to license terms.
26 */
27
28#if defined(__lint)
29
30int silence_lint_warnings = 0;
31
32#else /* __lint */
33
34#include <sys/multiboot.h>
35#include <sys/asm_linkage.h>
36#include <sys/segments.h>
37#include <sys/controlregs.h>
38
39#include "dboot_xboot.h"
40
41	.text
42	.globl _start
43_start:
44	jmp	code_start
45
46	/*
47	 * The multiboot header has to be at the start of the file
48	 *
49	 * The 32 bit kernel is ELF32, so the MB header is mostly ignored.
50	 *
51	 * The 64 bit kernel is ELF64, so we get grub to load the entire
52	 * ELF file into memory and trick it into jumping into this code.
53	 * The trick is done by a binary utility run after unix is linked,
54	 * that rewrites the mb_header.
55	 */
56	.align 4
57	.globl	mb_header
58mb_header:
59	.long	MB_HEADER_MAGIC	/* magic number */
60	.long	MB_HEADER_FLAGS	/* flags */
61	.long	MB_HEADER_CHECKSUM	/* checksum */
62	.long	0x11111111	/* header_addr: patched by elfpatch */
63	.long	0x100000	/* load_addr: patched by elfpatch */
64	.long	0		/* load_end_addr - 0 means entire file */
65	.long	0		/* bss_end_addr */
66	.long	0x2222222	/* entry_addr: patched by elfpatch */
67	.long	0		/* video mode.. */
68	.long	0		/* width 0 == don't care */
69	.long	0		/* height 0 == don't care */
70	.long	0		/* depth 0 == don't care */
71
72	/*
73	 * At entry we are in protected mode, 32 bit execution, paging and
74	 * interrupts are disabled.
75	 *
76	 * EAX == MB_BOOTLOADER_MAGIC
77	 * EBX points to multiboot information
78	 * segment registers all have segments with base 0, limit == 0xffffffff
79	 */
80code_start:
81	movl	%ebx, mb_info
82
83	movl	$stack_space, %esp	/* load my stack pointer */
84	addl	$STACK_SIZE, %esp
85
86	pushl	$0x0			/* push a dead-end frame */
87	pushl	$0x0
88	movl	%esp, %ebp
89
90	pushl	$0x0			/* clear all processor flags */
91	popf
92
93	/*
94	 * setup a global descriptor table with known contents
95	 */
96	lgdt	gdt_info
97	movw	$B32DATA_SEL, %ax
98	movw    %ax, %ds
99	movw    %ax, %es
100	movw    %ax, %fs
101	movw    %ax, %gs
102	movw    %ax, %ss
103	ljmp    $B32CODE_SEL, $newgdt
104newgdt:
105	nop
106
107	/*
108	 * go off and determine memory config, build page tables, etc.
109	 */
110	call	startup_kernel
111
112
113	/*
114	 * On amd64 we'll want the stack pointer to be 16 byte aligned.
115	 */
116	andl	$0xfffffff0, %esp
117
118	/*
119	 * Enable PGE, PAE and large pages
120	 */
121	movl	%cr4, %eax
122	testl	$1, pge_support
123	jz	1f
124	orl	$CR4_PGE, %eax
1251:
126	testl	$1, pae_support
127	jz	1f
128	orl	$CR4_PAE, %eax
1291:
130	testl	$1, largepage_support
131	jz	1f
132	orl	$CR4_PSE, %eax
1331:
134	movl	%eax, %cr4
135
136	/*
137	 * enable NX protection if processor supports it
138	 */
139	testl   $1, NX_support
140	jz      1f
141	movl    $MSR_AMD_EFER, %ecx
142	rdmsr
143	orl     $AMD_EFER_NXE, %eax
144	wrmsr
1451:
146
147
148	/*
149	 * load the pagetable base address into cr3
150	 */
151	movl	top_page_table, %eax
152	movl	%eax, %cr3
153
154#if defined(_BOOT_TARGET_amd64)
155	/*
156	 * enable long mode
157	 */
158	movl	$MSR_AMD_EFER, %ecx
159	rdmsr
160	orl	$AMD_EFER_LME, %eax
161	wrmsr
162#endif
163
164	/*
165	 * enable paging, write protection, alignment masking, but disable
166	 * the cache disable and write through only bits.
167	 */
168	movl	%cr0, %eax
169	orl	$_CONST(CR0_PG | CR0_WP | CR0_AM), %eax
170	andl	$_BITNOT(CR0_NW | CR0_CD), %eax
171	movl	%eax, %cr0
172	jmp	paging_on
173paging_on:
174
175	/*
176	 * The xboot_info ptr gets passed to the kernel as its argument
177	 */
178	movl	bi, %edi
179	movl	entry_addr_low, %esi
180
181#if defined(_BOOT_TARGET_i386)
182
183	pushl	%edi
184	call	*%esi
185
186#elif defined(_BOOT_TARGET_amd64)
187
188	/*
189	 * We're still in compatibility mode with 32 bit execution.
190	 * Switch to 64 bit mode now by switching to a 64 bit code segment.
191	 * then set up and do a lret to get into 64 bit execution.
192	 */
193	pushl	$B64CODE_SEL
194	pushl	$longmode
195	lret
196longmode:
197	.code64
198	movq	$0xffffffff00000000,%rdx
199	orq	%rdx, %rsi		/* set upper bits of entry addr */
200	notq	%rdx
201	andq	%rdx, %rdi		/* clean %rdi for passing arg */
202	call	*%rsi
203
204#else
205#error	"undefined target"
206#endif
207
208	.code32
209
210	/*
211	 * if reset fails halt the system
212	 */
213	ENTRY_NP(dboot_halt)
214	hlt
215	SET_SIZE(dboot_halt)
216
217	/*
218	 * flush the TLB
219	 */
220	ENTRY_NP(reload_cr3)
221	movl	%cr3, %eax
222	movl	%eax, %cr3
223	ret
224	SET_SIZE(reload_cr3)
225
226	/*
227	 * Detect if we can do cpuid, see if we can change bit 21 of eflags.
228	 * Note we don't do the bizarre tests for Cyrix CPUs in ml/locore.s.
229	 * If you're on such a CPU, you're stuck with non-PAE 32 bit kernels.
230	 */
231	ENTRY_NP(have_cpuid)
232	pushf
233	pushf
234	xorl	%eax, %eax
235	popl	%ecx
236	movl	%ecx, %edx
237	xorl	$0x200000, %ecx
238	pushl	%ecx
239	popf
240	pushf
241	popl	%ecx
242	cmpl	%ecx, %edx
243	setne	%al
244	popf
245	ret
246	SET_SIZE(have_cpuid)
247
248	/*
249	 * We want the GDT to be on its own page for better performance
250	 * running under hypervisors.
251	 */
252	.skip 4096
253#include "../boot/boot_gdt.s"
254	.skip 4096
255	.long	0
256
257#endif /* __lint */
258