xref: /titanic_52/usr/src/uts/i86pc/dboot/dboot_grub.s (revision c2cb63342c63c60cee771d1af82f377e34aa1217)
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#if defined(__lint)
30
31int silence_lint_warnings = 0;
32
33#else /* __lint */
34
35#include <sys/multiboot.h>
36#include <sys/asm_linkage.h>
37#include <sys/segments.h>
38#include <sys/controlregs.h>
39
40#include "dboot_xboot.h"
41
42	.text
43	.globl _start
44_start:
45	jmp	code_start
46
47	/*
48	 * The multiboot header has to be at the start of the file
49	 *
50	 * The 32 bit kernel is ELF32, so the MB header is mostly ignored.
51	 *
52	 * The 64 bit kernel is ELF64, so we get grub to load the entire
53	 * ELF file into memory and trick it into jumping into this code.
54	 * The trick is done by a binary utility run after unix is linked,
55	 * that rewrites the mb_header.
56	 */
57	.align 4
58	.globl	mb_header
59mb_header:
60	.long	MB_HEADER_MAGIC	/* magic number */
61	.long	MB_HEADER_FLAGS	/* flags */
62	.long	MB_HEADER_CHECKSUM	/* checksum */
63	.long	0x11111111	/* header_addr: patched by elfpatch */
64	.long	0x100000	/* load_addr: patched by elfpatch */
65	.long	0		/* load_end_addr - 0 means entire file */
66	.long	0		/* bss_end_addr */
67	.long	0x2222222	/* entry_addr: patched by elfpatch */
68	.long	0		/* video mode.. */
69	.long	0		/* width 0 == don't care */
70	.long	0		/* height 0 == don't care */
71	.long	0		/* depth 0 == don't care */
72
73	/*
74	 * At entry we are in protected mode, 32 bit execution, paging and
75	 * interrupts are disabled.
76	 *
77	 * EAX == 0x2BADB002
78	 * EBX points to multiboot information
79	 * segment registers all have segments with base 0, limit == 0xffffffff
80	 */
81code_start:
82	movl	%ebx, mb_info
83
84	movl	$stack_space, %esp	/* load my stack pointer */
85	addl	$STACK_SIZE, %esp
86
87	pushl	$0x0			/* push a dead-end frame */
88	pushl	$0x0
89	movl	%esp, %ebp
90
91	pushl	$0x0			/* clear all processor flags */
92	popf
93
94	/*
95	 * setup a global descriptor table with known contents
96	 */
97	lgdt	gdt_info
98	movw	$B32DATA_SEL, %ax
99	movw    %ax, %ds
100	movw    %ax, %es
101	movw    %ax, %fs
102	movw    %ax, %gs
103	movw    %ax, %ss
104	ljmp    $B32CODE_SEL, $newgdt
105newgdt:
106	nop
107
108	/*
109	 * go off and determine memory config, build page tables, etc.
110	 */
111	call	startup_kernel
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
166	 */
167	movl	%cr0, %eax
168	orl	$CR0_PG, %eax
169	movl	%eax, %cr0
170	jmp	paging_on
171paging_on:
172
173	/*
174	 * The xboot_info ptr gets passed to the kernel as its argument
175	 */
176	movl	bi, %edi
177	movl	entry_addr_low, %esi
178
179#if defined(_BOOT_TARGET_i386)
180
181	pushl	%edi
182	call	*%esi
183
184#elif defined(_BOOT_TARGET_amd64)
185
186	/*
187	 * We're still in compatibility mode with 32 bit execution.
188	 * Switch to 64 bit mode now by switching to a 64 bit code segment.
189	 * then set up and do a lret to get into 64 bit execution.
190	 */
191	pushl	$B64CODE_SEL
192	pushl	$longmode
193	lret
194longmode:
195	.code64
196	movq	$0xffffffff00000000,%rdx
197	orq	%rdx, %rsi		/* set upper bits of entry addr */
198	notq	%rdx
199	andq	%rdx, %rdi		/* clean %rdi for passing arg */
200	call	*%rsi
201
202#else
203#error	"undefined target"
204#endif
205
206	.code32
207
208	/*
209	 * uint8_t inb(int port)
210	 */
211	ENTRY_NP(inb)
212	movl	4(%esp), %edx
213	inb	(%dx)
214	andl	$0xff, %eax
215	ret
216	SET_SIZE(inb)
217
218	/*
219	 * void outb(int port, uint8_t value)
220	 */
221	ENTRY_NP(outb)
222	movl	4(%esp), %edx
223	movl	8(%esp), %eax
224	outb	(%dx)
225	ret
226	SET_SIZE(outb)
227
228	/*
229	 * if reset fails halt the system
230	 */
231	ENTRY_NP(dboot_halt)
232	hlt
233	SET_SIZE(dboot_halt)
234
235	/*
236	 * flush the TLB
237	 */
238	ENTRY_NP(reload_cr3)
239	movl	%cr3, %eax
240	movl	%eax, %cr3
241	ret
242	SET_SIZE(reload_cr3)
243
244	/*
245	 * do a cpuid instruction, returning the eax/edx values
246	 */
247	ENTRY_NP(get_cpuid_edx)
248	movl	4(%esp), %ecx
249	movl	(%ecx), %eax
250	pushl	%ebx
251	cpuid
252	popl	%ebx
253	movl	4(%esp), %ecx
254	movl	%eax, (%ecx)
255	movl	%edx, %eax
256	ret
257	SET_SIZE(get_cpuid_edx)
258
259	/*
260	 * Detect if we can do cpuid, see if we can change bit 21 of eflags.
261	 * Note we don't do the bizarre tests for Cyrix CPUs in ml/locore.s.
262	 * If you're on such a CPU, you're stuck with non-PAE 32 bit kernels.
263	 */
264	ENTRY_NP(have_cpuid)
265	pushf
266	pushf
267	xorl	%eax, %eax
268	popl	%ecx
269	movl	%ecx, %edx
270	xorl	$0x200000, %ecx
271	pushl	%ecx
272	popf
273	pushf
274	popl	%ecx
275	cmpl	%ecx, %edx
276	setne	%al
277	popf
278	ret
279	SET_SIZE(have_cpuid)
280
281#include "../boot/boot_gdt.s"
282
283#endif /* __lint */
284