xref: /titanic_52/usr/src/uts/i86pc/dboot/dboot_grub.s (revision d2670fc40c4567a1426992012f9a8666e3fa1098)
1ae115bc7Smrj/*
2ae115bc7Smrj * CDDL HEADER START
3ae115bc7Smrj *
4ae115bc7Smrj * The contents of this file are subject to the terms of the
5ae115bc7Smrj * Common Development and Distribution License (the "License").
6ae115bc7Smrj * You may not use this file except in compliance with the License.
7ae115bc7Smrj *
8ae115bc7Smrj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9ae115bc7Smrj * or http://www.opensolaris.org/os/licensing.
10ae115bc7Smrj * See the License for the specific language governing permissions
11ae115bc7Smrj * and limitations under the License.
12ae115bc7Smrj *
13ae115bc7Smrj * When distributing Covered Code, include this CDDL HEADER in each
14ae115bc7Smrj * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15ae115bc7Smrj * If applicable, add the following below this CDDL HEADER, with the
16ae115bc7Smrj * fields enclosed by brackets "[]" replaced with your own identifying
17ae115bc7Smrj * information: Portions Copyright [yyyy] [name of copyright owner]
18ae115bc7Smrj *
19ae115bc7Smrj * CDDL HEADER END
20ae115bc7Smrj */
21ae115bc7Smrj
22ae115bc7Smrj/*
235420b805SSeth Goldberg * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24ae115bc7Smrj * Use is subject to license terms.
25ae115bc7Smrj */
26ae115bc7Smrj
27ae115bc7Smrj#if defined(__lint)
28ae115bc7Smrj
29ae115bc7Smrjint silence_lint_warnings = 0;
30ae115bc7Smrj
31ae115bc7Smrj#else /* __lint */
32ae115bc7Smrj
33ae115bc7Smrj#include <sys/multiboot.h>
34*d2670fc4SToomas Soome#include <sys/multiboot2.h>
35ae115bc7Smrj#include <sys/asm_linkage.h>
36ae115bc7Smrj#include <sys/segments.h>
37ae115bc7Smrj#include <sys/controlregs.h>
38ae115bc7Smrj
39ae115bc7Smrj#include "dboot_xboot.h"
40ae115bc7Smrj
41ae115bc7Smrj	.text
42ae115bc7Smrj	.globl _start
43ae115bc7Smrj_start:
44ae115bc7Smrj	jmp	code_start
45ae115bc7Smrj
46ae115bc7Smrj	/*
47ae115bc7Smrj	 * The multiboot header has to be at the start of the file
48ae115bc7Smrj	 *
49ae115bc7Smrj	 * The 32 bit kernel is ELF32, so the MB header is mostly ignored.
50ae115bc7Smrj	 *
51ae115bc7Smrj	 * The 64 bit kernel is ELF64, so we get grub to load the entire
52ae115bc7Smrj	 * ELF file into memory and trick it into jumping into this code.
53ae115bc7Smrj	 * The trick is done by a binary utility run after unix is linked,
54ae115bc7Smrj	 * that rewrites the mb_header.
55ae115bc7Smrj	 */
56ae115bc7Smrj	.align 4
57ae115bc7Smrj	.globl	mb_header
58ae115bc7Smrjmb_header:
59ae115bc7Smrj	.long	MB_HEADER_MAGIC	/* magic number */
605420b805SSeth Goldberg#if defined(_BOOT_TARGET_i386)
615420b805SSeth Goldberg	.long	MB_HEADER_FLAGS_32	/* flags */
625420b805SSeth Goldberg	.long	MB_HEADER_CHECKSUM_32	/* checksum */
635420b805SSeth Goldberg#elif defined (_BOOT_TARGET_amd64)
645420b805SSeth Goldberg	.long	MB_HEADER_FLAGS_64	/* flags */
655420b805SSeth Goldberg	.long	MB_HEADER_CHECKSUM_64	/* checksum */
665420b805SSeth Goldberg#else
675420b805SSeth Goldberg#error No architecture defined
685420b805SSeth Goldberg#endif
695420b805SSeth Goldberg	.long	0x11111111	/* header_addr: patched by mbh_patch */
705420b805SSeth Goldberg	.long	0x100000	/* load_addr: patched by mbh_patch */
71ae115bc7Smrj	.long	0		/* load_end_addr - 0 means entire file */
72ae115bc7Smrj	.long	0		/* bss_end_addr */
735420b805SSeth Goldberg	.long	0x2222222	/* entry_addr: patched by mbh_patch */
74ae115bc7Smrj	.long	0		/* video mode.. */
75ae115bc7Smrj	.long	0		/* width 0 == don't care */
76ae115bc7Smrj	.long	0		/* height 0 == don't care */
77ae115bc7Smrj	.long	0		/* depth 0 == don't care */
78ae115bc7Smrj
79*d2670fc4SToomas Soome#if defined(_BOOT_TARGET_i386)
80*d2670fc4SToomas Soome	/*
81*d2670fc4SToomas Soome	 * The MB2 header must be 8 byte aligned relative to the beginning of
82*d2670fc4SToomas Soome	 * the in-memory ELF object. The 32-bit kernel ELF file has sections
83*d2670fc4SToomas Soome	 * which are 4-byte aligned, and as .align family directives only do
84*d2670fc4SToomas Soome	 * control the alignment inside the section, we need to construct the
85*d2670fc4SToomas Soome	 * image manually, by inserting the padding where needed. The alignment
86*d2670fc4SToomas Soome	 * setup here depends on the first PT_LOAD section of the ELF file, if
87*d2670fc4SToomas Soome	 * this section offset will change, this code must be reviewed.
88*d2670fc4SToomas Soome	 * Similarily, if we add extra tag types into the information request
89*d2670fc4SToomas Soome	 * or add tags into the tag list.
90*d2670fc4SToomas Soome	 */
91*d2670fc4SToomas Soome	.long	0		/* padding */
92*d2670fc4SToomas Soome#else
93*d2670fc4SToomas Soome	.balign	MULTIBOOT_HEADER_ALIGN
94*d2670fc4SToomas Soome#endif
95*d2670fc4SToomas Soomemb2_header:
96*d2670fc4SToomas Soome	.long	MULTIBOOT2_HEADER_MAGIC
97*d2670fc4SToomas Soome	.long	MULTIBOOT_ARCHITECTURE_I386
98*d2670fc4SToomas Soome	.long	mb2_header_end - mb2_header
99*d2670fc4SToomas Soome	.long	-(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE_I386 + (mb2_header_end - mb2_header))
100*d2670fc4SToomas Soome
101*d2670fc4SToomas Soome	/*
102*d2670fc4SToomas Soome	 * Multiboot 2 tags follow. Note, the first tag immediately follows
103*d2670fc4SToomas Soome	 * the header. Subsequent tags must be aligned by MULTIBOOT_TAG_ALIGN.
104*d2670fc4SToomas Soome	 *
105*d2670fc4SToomas Soome	 * MB information request tag.
106*d2670fc4SToomas Soome	 */
107*d2670fc4SToomas Soomeinformation_request_tag_start:
108*d2670fc4SToomas Soome	.word	MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST
109*d2670fc4SToomas Soome	.word	0
110*d2670fc4SToomas Soome	.long	information_request_tag_end - information_request_tag_start
111*d2670fc4SToomas Soome	.long	MULTIBOOT_TAG_TYPE_CMDLINE
112*d2670fc4SToomas Soome	.long	MULTIBOOT_TAG_TYPE_MODULE
113*d2670fc4SToomas Soome	.long	MULTIBOOT_TAG_TYPE_BOOTDEV
114*d2670fc4SToomas Soome	.long	MULTIBOOT_TAG_TYPE_MMAP
115*d2670fc4SToomas Soome	.long	MULTIBOOT_TAG_TYPE_BASIC_MEMINFO
116*d2670fc4SToomas Soomeinformation_request_tag_end:
117*d2670fc4SToomas Soome	.long	0		/* padding */
118*d2670fc4SToomas Soome
119*d2670fc4SToomas Soome#if defined (_BOOT_TARGET_amd64)
120*d2670fc4SToomas Soome	/*
121*d2670fc4SToomas Soome	 * The following values are patched by mbh_patch for the 64-bit kernel,
122*d2670fc4SToomas Soome	 * so we only provide this tag for the 64-bit kernel.
123*d2670fc4SToomas Soome	 */
124*d2670fc4SToomas Soome	.balign	MULTIBOOT_TAG_ALIGN
125*d2670fc4SToomas Soomeaddress_tag_start:
126*d2670fc4SToomas Soome	.word	MULTIBOOT_HEADER_TAG_ADDRESS
127*d2670fc4SToomas Soome	.word	0
128*d2670fc4SToomas Soome	.long	address_tag_end - address_tag_start
129*d2670fc4SToomas Soome	.long	mb2_header
130*d2670fc4SToomas Soome	.globl	mb2_load_addr
131*d2670fc4SToomas Soomemb2_load_addr:
132*d2670fc4SToomas Soome	.long	0		/* load addr */
133*d2670fc4SToomas Soome	.long	0		/* load_end_addr */
134*d2670fc4SToomas Soome	.long	0		/* bss_end_addr */
135*d2670fc4SToomas Soomeaddress_tag_end:
136*d2670fc4SToomas Soome	/*
137*d2670fc4SToomas Soome	 * entry address tag
138*d2670fc4SToomas Soome	 */
139*d2670fc4SToomas Soome	.balign	MULTIBOOT_TAG_ALIGN
140*d2670fc4SToomas Soomeentry_address_tag_start:
141*d2670fc4SToomas Soome	.word	MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS
142*d2670fc4SToomas Soome	.word	0
143*d2670fc4SToomas Soome	.long	entry_address_tag_end - entry_address_tag_start
144*d2670fc4SToomas Soome	.long	0		/* entry addr */
145*d2670fc4SToomas Soomeentry_address_tag_end:
146*d2670fc4SToomas Soome
147*d2670fc4SToomas Soome	.balign	MULTIBOOT_TAG_ALIGN	/* Alignment for the next tag */
148*d2670fc4SToomas Soome#endif
149*d2670fc4SToomas Soome	/*
150*d2670fc4SToomas Soome	 * MB console flags tag
151*d2670fc4SToomas Soome	 */
152*d2670fc4SToomas Soomeconsole_tag_start:
153*d2670fc4SToomas Soome	.word	MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS
154*d2670fc4SToomas Soome	.word	0
155*d2670fc4SToomas Soome	.long	console_tag_end - console_tag_start
156*d2670fc4SToomas Soome	.long	MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED
157*d2670fc4SToomas Soomeconsole_tag_end:
158*d2670fc4SToomas Soome	.long	0		/* padding */
159*d2670fc4SToomas Soome
160*d2670fc4SToomas Soome	/*
161*d2670fc4SToomas Soome	 * Tell the bootloader to load the modules page aligned to
162*d2670fc4SToomas Soome	 * the specified alignment.
163*d2670fc4SToomas Soome	 */
164*d2670fc4SToomas Soome	.word	MULTIBOOT_HEADER_TAG_MODULE_ALIGN
165*d2670fc4SToomas Soome	.word	0
166*d2670fc4SToomas Soome	.long	8
167*d2670fc4SToomas Soome
168*d2670fc4SToomas Soome	/*
169*d2670fc4SToomas Soome	 * Termination tag.
170*d2670fc4SToomas Soome	 */
171*d2670fc4SToomas Soome	.word	MULTIBOOT_HEADER_TAG_END
172*d2670fc4SToomas Soome	.word	0
173*d2670fc4SToomas Soome	.long	8
174*d2670fc4SToomas Soomemb2_header_end:
175*d2670fc4SToomas Soome
176ae115bc7Smrj	/*
177ae115bc7Smrj	 * At entry we are in protected mode, 32 bit execution, paging and
178ae115bc7Smrj	 * interrupts are disabled.
179ae115bc7Smrj	 *
18019397407SSherry Moore	 * EAX == MB_BOOTLOADER_MAGIC
181ae115bc7Smrj	 * EBX points to multiboot information
182ae115bc7Smrj	 * segment registers all have segments with base 0, limit == 0xffffffff
183ae115bc7Smrj	 */
184ae115bc7Smrjcode_start:
185*d2670fc4SToomas Soome	movl	%eax, mb_magic
186*d2670fc4SToomas Soome	movl	%ebx, mb_addr
187ae115bc7Smrj
188ae115bc7Smrj	movl	$stack_space, %esp	/* load my stack pointer */
189ae115bc7Smrj	addl	$STACK_SIZE, %esp
190ae115bc7Smrj
191ae115bc7Smrj	pushl	$0x0			/* push a dead-end frame */
192ae115bc7Smrj	pushl	$0x0
193ae115bc7Smrj	movl	%esp, %ebp
194ae115bc7Smrj
195ae115bc7Smrj	pushl	$0x0			/* clear all processor flags */
196ae115bc7Smrj	popf
197ae115bc7Smrj
198ae115bc7Smrj	/*
199ae115bc7Smrj	 * setup a global descriptor table with known contents
200ae115bc7Smrj	 */
201ae115bc7Smrj	lgdt	gdt_info
202ae115bc7Smrj	movw	$B32DATA_SEL, %ax
203ae115bc7Smrj	movw    %ax, %ds
204ae115bc7Smrj	movw    %ax, %es
205ae115bc7Smrj	movw    %ax, %fs
206ae115bc7Smrj	movw    %ax, %gs
207ae115bc7Smrj	movw    %ax, %ss
208ae115bc7Smrj	ljmp    $B32CODE_SEL, $newgdt
209ae115bc7Smrjnewgdt:
210ae115bc7Smrj	nop
211ae115bc7Smrj
212ae115bc7Smrj	/*
213ae115bc7Smrj	 * go off and determine memory config, build page tables, etc.
214ae115bc7Smrj	 */
215ae115bc7Smrj	call	startup_kernel
216ae115bc7Smrj
21719397407SSherry Moore
218ae115bc7Smrj	/*
219ae115bc7Smrj	 * On amd64 we'll want the stack pointer to be 16 byte aligned.
220ae115bc7Smrj	 */
221ae115bc7Smrj	andl	$0xfffffff0, %esp
222ae115bc7Smrj
223ae115bc7Smrj	/*
224ae115bc7Smrj	 * Enable PGE, PAE and large pages
225ae115bc7Smrj	 */
226ae115bc7Smrj	movl	%cr4, %eax
227ae115bc7Smrj	testl	$1, pge_support
228ae115bc7Smrj	jz	1f
229ae115bc7Smrj	orl	$CR4_PGE, %eax
230ae115bc7Smrj1:
231ae115bc7Smrj	testl	$1, pae_support
232ae115bc7Smrj	jz	1f
233ae115bc7Smrj	orl	$CR4_PAE, %eax
234ae115bc7Smrj1:
235ae115bc7Smrj	testl	$1, largepage_support
236ae115bc7Smrj	jz	1f
237ae115bc7Smrj	orl	$CR4_PSE, %eax
238ae115bc7Smrj1:
239ae115bc7Smrj	movl	%eax, %cr4
240ae115bc7Smrj
241ae115bc7Smrj	/*
242ae115bc7Smrj	 * enable NX protection if processor supports it
243ae115bc7Smrj	 */
244ae115bc7Smrj	testl   $1, NX_support
245ae115bc7Smrj	jz      1f
246ae115bc7Smrj	movl    $MSR_AMD_EFER, %ecx
247ae115bc7Smrj	rdmsr
248ae115bc7Smrj	orl     $AMD_EFER_NXE, %eax
249ae115bc7Smrj	wrmsr
250ae115bc7Smrj1:
251ae115bc7Smrj
252ae115bc7Smrj
253ae115bc7Smrj	/*
254ae115bc7Smrj	 * load the pagetable base address into cr3
255ae115bc7Smrj	 */
256ae115bc7Smrj	movl	top_page_table, %eax
257ae115bc7Smrj	movl	%eax, %cr3
258ae115bc7Smrj
259ae115bc7Smrj#if defined(_BOOT_TARGET_amd64)
260ae115bc7Smrj	/*
261ae115bc7Smrj	 * enable long mode
262ae115bc7Smrj	 */
263ae115bc7Smrj	movl	$MSR_AMD_EFER, %ecx
264ae115bc7Smrj	rdmsr
265ae115bc7Smrj	orl	$AMD_EFER_LME, %eax
266ae115bc7Smrj	wrmsr
267ae115bc7Smrj#endif
268ae115bc7Smrj
269ae115bc7Smrj	/*
270843e1988Sjohnlev	 * enable paging, write protection, alignment masking, but disable
271843e1988Sjohnlev	 * the cache disable and write through only bits.
272ae115bc7Smrj	 */
273ae115bc7Smrj	movl	%cr0, %eax
274843e1988Sjohnlev	orl	$_CONST(CR0_PG | CR0_WP | CR0_AM), %eax
275843e1988Sjohnlev	andl	$_BITNOT(CR0_NW | CR0_CD), %eax
276ae115bc7Smrj	movl	%eax, %cr0
277ae115bc7Smrj	jmp	paging_on
278ae115bc7Smrjpaging_on:
279ae115bc7Smrj
280ae115bc7Smrj	/*
281ae115bc7Smrj	 * The xboot_info ptr gets passed to the kernel as its argument
282ae115bc7Smrj	 */
283ae115bc7Smrj	movl	bi, %edi
284ae115bc7Smrj	movl	entry_addr_low, %esi
285ae115bc7Smrj
286ae115bc7Smrj#if defined(_BOOT_TARGET_i386)
287ae115bc7Smrj
288ae115bc7Smrj	pushl	%edi
289ae115bc7Smrj	call	*%esi
290ae115bc7Smrj
291ae115bc7Smrj#elif defined(_BOOT_TARGET_amd64)
292ae115bc7Smrj
293ae115bc7Smrj	/*
294ae115bc7Smrj	 * We're still in compatibility mode with 32 bit execution.
295ae115bc7Smrj	 * Switch to 64 bit mode now by switching to a 64 bit code segment.
296ae115bc7Smrj	 * then set up and do a lret to get into 64 bit execution.
297ae115bc7Smrj	 */
298ae115bc7Smrj	pushl	$B64CODE_SEL
299ae115bc7Smrj	pushl	$longmode
300ae115bc7Smrj	lret
301ae115bc7Smrjlongmode:
302ae115bc7Smrj	.code64
303ae115bc7Smrj	movq	$0xffffffff00000000,%rdx
304ae115bc7Smrj	orq	%rdx, %rsi		/* set upper bits of entry addr */
305ae115bc7Smrj	notq	%rdx
306ae115bc7Smrj	andq	%rdx, %rdi		/* clean %rdi for passing arg */
307ae115bc7Smrj	call	*%rsi
308ae115bc7Smrj
309ae115bc7Smrj#else
310ae115bc7Smrj#error	"undefined target"
311ae115bc7Smrj#endif
312ae115bc7Smrj
313ae115bc7Smrj	.code32
314ae115bc7Smrj
315ae115bc7Smrj	/*
316ae115bc7Smrj	 * if reset fails halt the system
317ae115bc7Smrj	 */
318ae115bc7Smrj	ENTRY_NP(dboot_halt)
319ae115bc7Smrj	hlt
320ae115bc7Smrj	SET_SIZE(dboot_halt)
321ae115bc7Smrj
322ae115bc7Smrj	/*
323ae115bc7Smrj	 * flush the TLB
324ae115bc7Smrj	 */
325ae115bc7Smrj	ENTRY_NP(reload_cr3)
326ae115bc7Smrj	movl	%cr3, %eax
327ae115bc7Smrj	movl	%eax, %cr3
328ae115bc7Smrj	ret
329ae115bc7Smrj	SET_SIZE(reload_cr3)
330ae115bc7Smrj
331ae115bc7Smrj	/*
332ae115bc7Smrj	 * Detect if we can do cpuid, see if we can change bit 21 of eflags.
333ae115bc7Smrj	 * Note we don't do the bizarre tests for Cyrix CPUs in ml/locore.s.
334ae115bc7Smrj	 * If you're on such a CPU, you're stuck with non-PAE 32 bit kernels.
335ae115bc7Smrj	 */
336ae115bc7Smrj	ENTRY_NP(have_cpuid)
337ae115bc7Smrj	pushf
338ae115bc7Smrj	pushf
339ae115bc7Smrj	xorl	%eax, %eax
340ae115bc7Smrj	popl	%ecx
341ae115bc7Smrj	movl	%ecx, %edx
342ae115bc7Smrj	xorl	$0x200000, %ecx
343ae115bc7Smrj	pushl	%ecx
344ae115bc7Smrj	popf
345ae115bc7Smrj	pushf
346ae115bc7Smrj	popl	%ecx
347ae115bc7Smrj	cmpl	%ecx, %edx
348ae115bc7Smrj	setne	%al
349ae115bc7Smrj	popf
350ae115bc7Smrj	ret
351ae115bc7Smrj	SET_SIZE(have_cpuid)
352ae115bc7Smrj
3530cfdb603Sjosephb	/*
3540cfdb603Sjosephb	 * We want the GDT to be on its own page for better performance
3550cfdb603Sjosephb	 * running under hypervisors.
3560cfdb603Sjosephb	 */
3570cfdb603Sjosephb	.skip 4096
358ae115bc7Smrj#include "../boot/boot_gdt.s"
3590cfdb603Sjosephb	.skip 4096
3600cfdb603Sjosephb	.long	0
361ae115bc7Smrj
362ae115bc7Smrj#endif /* __lint */
363