xref: /titanic_52/usr/src/uts/i86pc/dboot/dboot_grub.s (revision d2670fc40c4567a1426992012f9a8666e3fa1098)
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 2009 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#if defined(__lint)
28
29int silence_lint_warnings = 0;
30
31#else /* __lint */
32
33#include <sys/multiboot.h>
34#include <sys/multiboot2.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#if defined(_BOOT_TARGET_i386)
61	.long	MB_HEADER_FLAGS_32	/* flags */
62	.long	MB_HEADER_CHECKSUM_32	/* checksum */
63#elif defined (_BOOT_TARGET_amd64)
64	.long	MB_HEADER_FLAGS_64	/* flags */
65	.long	MB_HEADER_CHECKSUM_64	/* checksum */
66#else
67#error No architecture defined
68#endif
69	.long	0x11111111	/* header_addr: patched by mbh_patch */
70	.long	0x100000	/* load_addr: patched by mbh_patch */
71	.long	0		/* load_end_addr - 0 means entire file */
72	.long	0		/* bss_end_addr */
73	.long	0x2222222	/* entry_addr: patched by mbh_patch */
74	.long	0		/* video mode.. */
75	.long	0		/* width 0 == don't care */
76	.long	0		/* height 0 == don't care */
77	.long	0		/* depth 0 == don't care */
78
79#if defined(_BOOT_TARGET_i386)
80	/*
81	 * The MB2 header must be 8 byte aligned relative to the beginning of
82	 * the in-memory ELF object. The 32-bit kernel ELF file has sections
83	 * which are 4-byte aligned, and as .align family directives only do
84	 * control the alignment inside the section, we need to construct the
85	 * image manually, by inserting the padding where needed. The alignment
86	 * setup here depends on the first PT_LOAD section of the ELF file, if
87	 * this section offset will change, this code must be reviewed.
88	 * Similarily, if we add extra tag types into the information request
89	 * or add tags into the tag list.
90	 */
91	.long	0		/* padding */
92#else
93	.balign	MULTIBOOT_HEADER_ALIGN
94#endif
95mb2_header:
96	.long	MULTIBOOT2_HEADER_MAGIC
97	.long	MULTIBOOT_ARCHITECTURE_I386
98	.long	mb2_header_end - mb2_header
99	.long	-(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE_I386 + (mb2_header_end - mb2_header))
100
101	/*
102	 * Multiboot 2 tags follow. Note, the first tag immediately follows
103	 * the header. Subsequent tags must be aligned by MULTIBOOT_TAG_ALIGN.
104	 *
105	 * MB information request tag.
106	 */
107information_request_tag_start:
108	.word	MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST
109	.word	0
110	.long	information_request_tag_end - information_request_tag_start
111	.long	MULTIBOOT_TAG_TYPE_CMDLINE
112	.long	MULTIBOOT_TAG_TYPE_MODULE
113	.long	MULTIBOOT_TAG_TYPE_BOOTDEV
114	.long	MULTIBOOT_TAG_TYPE_MMAP
115	.long	MULTIBOOT_TAG_TYPE_BASIC_MEMINFO
116information_request_tag_end:
117	.long	0		/* padding */
118
119#if defined (_BOOT_TARGET_amd64)
120	/*
121	 * The following values are patched by mbh_patch for the 64-bit kernel,
122	 * so we only provide this tag for the 64-bit kernel.
123	 */
124	.balign	MULTIBOOT_TAG_ALIGN
125address_tag_start:
126	.word	MULTIBOOT_HEADER_TAG_ADDRESS
127	.word	0
128	.long	address_tag_end - address_tag_start
129	.long	mb2_header
130	.globl	mb2_load_addr
131mb2_load_addr:
132	.long	0		/* load addr */
133	.long	0		/* load_end_addr */
134	.long	0		/* bss_end_addr */
135address_tag_end:
136	/*
137	 * entry address tag
138	 */
139	.balign	MULTIBOOT_TAG_ALIGN
140entry_address_tag_start:
141	.word	MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS
142	.word	0
143	.long	entry_address_tag_end - entry_address_tag_start
144	.long	0		/* entry addr */
145entry_address_tag_end:
146
147	.balign	MULTIBOOT_TAG_ALIGN	/* Alignment for the next tag */
148#endif
149	/*
150	 * MB console flags tag
151	 */
152console_tag_start:
153	.word	MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS
154	.word	0
155	.long	console_tag_end - console_tag_start
156	.long	MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED
157console_tag_end:
158	.long	0		/* padding */
159
160	/*
161	 * Tell the bootloader to load the modules page aligned to
162	 * the specified alignment.
163	 */
164	.word	MULTIBOOT_HEADER_TAG_MODULE_ALIGN
165	.word	0
166	.long	8
167
168	/*
169	 * Termination tag.
170	 */
171	.word	MULTIBOOT_HEADER_TAG_END
172	.word	0
173	.long	8
174mb2_header_end:
175
176	/*
177	 * At entry we are in protected mode, 32 bit execution, paging and
178	 * interrupts are disabled.
179	 *
180	 * EAX == MB_BOOTLOADER_MAGIC
181	 * EBX points to multiboot information
182	 * segment registers all have segments with base 0, limit == 0xffffffff
183	 */
184code_start:
185	movl	%eax, mb_magic
186	movl	%ebx, mb_addr
187
188	movl	$stack_space, %esp	/* load my stack pointer */
189	addl	$STACK_SIZE, %esp
190
191	pushl	$0x0			/* push a dead-end frame */
192	pushl	$0x0
193	movl	%esp, %ebp
194
195	pushl	$0x0			/* clear all processor flags */
196	popf
197
198	/*
199	 * setup a global descriptor table with known contents
200	 */
201	lgdt	gdt_info
202	movw	$B32DATA_SEL, %ax
203	movw    %ax, %ds
204	movw    %ax, %es
205	movw    %ax, %fs
206	movw    %ax, %gs
207	movw    %ax, %ss
208	ljmp    $B32CODE_SEL, $newgdt
209newgdt:
210	nop
211
212	/*
213	 * go off and determine memory config, build page tables, etc.
214	 */
215	call	startup_kernel
216
217
218	/*
219	 * On amd64 we'll want the stack pointer to be 16 byte aligned.
220	 */
221	andl	$0xfffffff0, %esp
222
223	/*
224	 * Enable PGE, PAE and large pages
225	 */
226	movl	%cr4, %eax
227	testl	$1, pge_support
228	jz	1f
229	orl	$CR4_PGE, %eax
2301:
231	testl	$1, pae_support
232	jz	1f
233	orl	$CR4_PAE, %eax
2341:
235	testl	$1, largepage_support
236	jz	1f
237	orl	$CR4_PSE, %eax
2381:
239	movl	%eax, %cr4
240
241	/*
242	 * enable NX protection if processor supports it
243	 */
244	testl   $1, NX_support
245	jz      1f
246	movl    $MSR_AMD_EFER, %ecx
247	rdmsr
248	orl     $AMD_EFER_NXE, %eax
249	wrmsr
2501:
251
252
253	/*
254	 * load the pagetable base address into cr3
255	 */
256	movl	top_page_table, %eax
257	movl	%eax, %cr3
258
259#if defined(_BOOT_TARGET_amd64)
260	/*
261	 * enable long mode
262	 */
263	movl	$MSR_AMD_EFER, %ecx
264	rdmsr
265	orl	$AMD_EFER_LME, %eax
266	wrmsr
267#endif
268
269	/*
270	 * enable paging, write protection, alignment masking, but disable
271	 * the cache disable and write through only bits.
272	 */
273	movl	%cr0, %eax
274	orl	$_CONST(CR0_PG | CR0_WP | CR0_AM), %eax
275	andl	$_BITNOT(CR0_NW | CR0_CD), %eax
276	movl	%eax, %cr0
277	jmp	paging_on
278paging_on:
279
280	/*
281	 * The xboot_info ptr gets passed to the kernel as its argument
282	 */
283	movl	bi, %edi
284	movl	entry_addr_low, %esi
285
286#if defined(_BOOT_TARGET_i386)
287
288	pushl	%edi
289	call	*%esi
290
291#elif defined(_BOOT_TARGET_amd64)
292
293	/*
294	 * We're still in compatibility mode with 32 bit execution.
295	 * Switch to 64 bit mode now by switching to a 64 bit code segment.
296	 * then set up and do a lret to get into 64 bit execution.
297	 */
298	pushl	$B64CODE_SEL
299	pushl	$longmode
300	lret
301longmode:
302	.code64
303	movq	$0xffffffff00000000,%rdx
304	orq	%rdx, %rsi		/* set upper bits of entry addr */
305	notq	%rdx
306	andq	%rdx, %rdi		/* clean %rdi for passing arg */
307	call	*%rsi
308
309#else
310#error	"undefined target"
311#endif
312
313	.code32
314
315	/*
316	 * if reset fails halt the system
317	 */
318	ENTRY_NP(dboot_halt)
319	hlt
320	SET_SIZE(dboot_halt)
321
322	/*
323	 * flush the TLB
324	 */
325	ENTRY_NP(reload_cr3)
326	movl	%cr3, %eax
327	movl	%eax, %cr3
328	ret
329	SET_SIZE(reload_cr3)
330
331	/*
332	 * Detect if we can do cpuid, see if we can change bit 21 of eflags.
333	 * Note we don't do the bizarre tests for Cyrix CPUs in ml/locore.s.
334	 * If you're on such a CPU, you're stuck with non-PAE 32 bit kernels.
335	 */
336	ENTRY_NP(have_cpuid)
337	pushf
338	pushf
339	xorl	%eax, %eax
340	popl	%ecx
341	movl	%ecx, %edx
342	xorl	$0x200000, %ecx
343	pushl	%ecx
344	popf
345	pushf
346	popl	%ecx
347	cmpl	%ecx, %edx
348	setne	%al
349	popf
350	ret
351	SET_SIZE(have_cpuid)
352
353	/*
354	 * We want the GDT to be on its own page for better performance
355	 * running under hypervisors.
356	 */
357	.skip 4096
358#include "../boot/boot_gdt.s"
359	.skip 4096
360	.long	0
361
362#endif /* __lint */
363