xref: /onnv-gate/usr/src/uts/i86pc/dboot/dboot_grub.s (revision 10304:af5a60358231)
17656SSherry.Moore@Sun.COM
23446Smrj/*
33446Smrj * CDDL HEADER START
43446Smrj *
53446Smrj * The contents of this file are subject to the terms of the
63446Smrj * Common Development and Distribution License (the "License").
73446Smrj * You may not use this file except in compliance with the License.
83446Smrj *
93446Smrj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
103446Smrj * or http://www.opensolaris.org/os/licensing.
113446Smrj * See the License for the specific language governing permissions
123446Smrj * and limitations under the License.
133446Smrj *
143446Smrj * When distributing Covered Code, include this CDDL HEADER in each
153446Smrj * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
163446Smrj * If applicable, add the following below this CDDL HEADER, with the
173446Smrj * fields enclosed by brackets "[]" replaced with your own identifying
183446Smrj * information: Portions Copyright [yyyy] [name of copyright owner]
193446Smrj *
203446Smrj * CDDL HEADER END
213446Smrj */
223446Smrj
233446Smrj/*
24*10304SSeth.Goldberg@Sun.COM * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
253446Smrj * Use is subject to license terms.
263446Smrj */
273446Smrj
283446Smrj#if defined(__lint)
293446Smrj
303446Smrjint silence_lint_warnings = 0;
313446Smrj
323446Smrj#else /* __lint */
333446Smrj
343446Smrj#include <sys/multiboot.h>
353446Smrj#include <sys/asm_linkage.h>
363446Smrj#include <sys/segments.h>
373446Smrj#include <sys/controlregs.h>
383446Smrj
393446Smrj#include "dboot_xboot.h"
403446Smrj
413446Smrj	.text
423446Smrj	.globl _start
433446Smrj_start:
443446Smrj	jmp	code_start
453446Smrj
463446Smrj	/*
473446Smrj	 * The multiboot header has to be at the start of the file
483446Smrj	 *
493446Smrj	 * The 32 bit kernel is ELF32, so the MB header is mostly ignored.
503446Smrj	 *
513446Smrj	 * The 64 bit kernel is ELF64, so we get grub to load the entire
523446Smrj	 * ELF file into memory and trick it into jumping into this code.
533446Smrj	 * The trick is done by a binary utility run after unix is linked,
543446Smrj	 * that rewrites the mb_header.
553446Smrj	 */
563446Smrj	.align 4
573446Smrj	.globl	mb_header
583446Smrjmb_header:
593446Smrj	.long	MB_HEADER_MAGIC	/* magic number */
60*10304SSeth.Goldberg@Sun.COM#if defined(_BOOT_TARGET_i386)
61*10304SSeth.Goldberg@Sun.COM	.long	MB_HEADER_FLAGS_32	/* flags */
62*10304SSeth.Goldberg@Sun.COM	.long	MB_HEADER_CHECKSUM_32	/* checksum */
63*10304SSeth.Goldberg@Sun.COM#elif defined (_BOOT_TARGET_amd64)
64*10304SSeth.Goldberg@Sun.COM	.long	MB_HEADER_FLAGS_64	/* flags */
65*10304SSeth.Goldberg@Sun.COM	.long	MB_HEADER_CHECKSUM_64	/* checksum */
66*10304SSeth.Goldberg@Sun.COM#else
67*10304SSeth.Goldberg@Sun.COM#error No architecture defined
68*10304SSeth.Goldberg@Sun.COM#endif
69*10304SSeth.Goldberg@Sun.COM	.long	0x11111111	/* header_addr: patched by mbh_patch */
70*10304SSeth.Goldberg@Sun.COM	.long	0x100000	/* load_addr: patched by mbh_patch */
713446Smrj	.long	0		/* load_end_addr - 0 means entire file */
723446Smrj	.long	0		/* bss_end_addr */
73*10304SSeth.Goldberg@Sun.COM	.long	0x2222222	/* entry_addr: patched by mbh_patch */
743446Smrj	.long	0		/* video mode.. */
753446Smrj	.long	0		/* width 0 == don't care */
763446Smrj	.long	0		/* height 0 == don't care */
773446Smrj	.long	0		/* depth 0 == don't care */
783446Smrj
793446Smrj	/*
803446Smrj	 * At entry we are in protected mode, 32 bit execution, paging and
813446Smrj	 * interrupts are disabled.
823446Smrj	 *
837656SSherry.Moore@Sun.COM	 * EAX == MB_BOOTLOADER_MAGIC
843446Smrj	 * EBX points to multiboot information
853446Smrj	 * segment registers all have segments with base 0, limit == 0xffffffff
863446Smrj	 */
873446Smrjcode_start:
883446Smrj	movl	%ebx, mb_info
893446Smrj
903446Smrj	movl	$stack_space, %esp	/* load my stack pointer */
913446Smrj	addl	$STACK_SIZE, %esp
923446Smrj
933446Smrj	pushl	$0x0			/* push a dead-end frame */
943446Smrj	pushl	$0x0
953446Smrj	movl	%esp, %ebp
963446Smrj
973446Smrj	pushl	$0x0			/* clear all processor flags */
983446Smrj	popf
993446Smrj
1003446Smrj	/*
1013446Smrj	 * setup a global descriptor table with known contents
1023446Smrj	 */
1033446Smrj	lgdt	gdt_info
1043446Smrj	movw	$B32DATA_SEL, %ax
1053446Smrj	movw    %ax, %ds
1063446Smrj	movw    %ax, %es
1073446Smrj	movw    %ax, %fs
1083446Smrj	movw    %ax, %gs
1093446Smrj	movw    %ax, %ss
1103446Smrj	ljmp    $B32CODE_SEL, $newgdt
1113446Smrjnewgdt:
1123446Smrj	nop
1133446Smrj
1143446Smrj	/*
1153446Smrj	 * go off and determine memory config, build page tables, etc.
1163446Smrj	 */
1173446Smrj	call	startup_kernel
1183446Smrj
1197656SSherry.Moore@Sun.COM
1203446Smrj	/*
1213446Smrj	 * On amd64 we'll want the stack pointer to be 16 byte aligned.
1223446Smrj	 */
1233446Smrj	andl	$0xfffffff0, %esp
1243446Smrj
1253446Smrj	/*
1263446Smrj	 * Enable PGE, PAE and large pages
1273446Smrj	 */
1283446Smrj	movl	%cr4, %eax
1293446Smrj	testl	$1, pge_support
1303446Smrj	jz	1f
1313446Smrj	orl	$CR4_PGE, %eax
1323446Smrj1:
1333446Smrj	testl	$1, pae_support
1343446Smrj	jz	1f
1353446Smrj	orl	$CR4_PAE, %eax
1363446Smrj1:
1373446Smrj	testl	$1, largepage_support
1383446Smrj	jz	1f
1393446Smrj	orl	$CR4_PSE, %eax
1403446Smrj1:
1413446Smrj	movl	%eax, %cr4
1423446Smrj
1433446Smrj	/*
1443446Smrj	 * enable NX protection if processor supports it
1453446Smrj	 */
1463446Smrj	testl   $1, NX_support
1473446Smrj	jz      1f
1483446Smrj	movl    $MSR_AMD_EFER, %ecx
1493446Smrj	rdmsr
1503446Smrj	orl     $AMD_EFER_NXE, %eax
1513446Smrj	wrmsr
1523446Smrj1:
1533446Smrj
1543446Smrj
1553446Smrj	/*
1563446Smrj	 * load the pagetable base address into cr3
1573446Smrj	 */
1583446Smrj	movl	top_page_table, %eax
1593446Smrj	movl	%eax, %cr3
1603446Smrj
1613446Smrj#if defined(_BOOT_TARGET_amd64)
1623446Smrj	/*
1633446Smrj	 * enable long mode
1643446Smrj	 */
1653446Smrj	movl	$MSR_AMD_EFER, %ecx
1663446Smrj	rdmsr
1673446Smrj	orl	$AMD_EFER_LME, %eax
1683446Smrj	wrmsr
1693446Smrj#endif
1703446Smrj
1713446Smrj	/*
1725084Sjohnlev	 * enable paging, write protection, alignment masking, but disable
1735084Sjohnlev	 * the cache disable and write through only bits.
1743446Smrj	 */
1753446Smrj	movl	%cr0, %eax
1765084Sjohnlev	orl	$_CONST(CR0_PG | CR0_WP | CR0_AM), %eax
1775084Sjohnlev	andl	$_BITNOT(CR0_NW | CR0_CD), %eax
1783446Smrj	movl	%eax, %cr0
1793446Smrj	jmp	paging_on
1803446Smrjpaging_on:
1813446Smrj
1823446Smrj	/*
1833446Smrj	 * The xboot_info ptr gets passed to the kernel as its argument
1843446Smrj	 */
1853446Smrj	movl	bi, %edi
1863446Smrj	movl	entry_addr_low, %esi
1873446Smrj
1883446Smrj#if defined(_BOOT_TARGET_i386)
1893446Smrj
1903446Smrj	pushl	%edi
1913446Smrj	call	*%esi
1923446Smrj
1933446Smrj#elif defined(_BOOT_TARGET_amd64)
1943446Smrj
1953446Smrj	/*
1963446Smrj	 * We're still in compatibility mode with 32 bit execution.
1973446Smrj	 * Switch to 64 bit mode now by switching to a 64 bit code segment.
1983446Smrj	 * then set up and do a lret to get into 64 bit execution.
1993446Smrj	 */
2003446Smrj	pushl	$B64CODE_SEL
2013446Smrj	pushl	$longmode
2023446Smrj	lret
2033446Smrjlongmode:
2043446Smrj	.code64
2053446Smrj	movq	$0xffffffff00000000,%rdx
2063446Smrj	orq	%rdx, %rsi		/* set upper bits of entry addr */
2073446Smrj	notq	%rdx
2083446Smrj	andq	%rdx, %rdi		/* clean %rdi for passing arg */
2093446Smrj	call	*%rsi
2103446Smrj
2113446Smrj#else
2123446Smrj#error	"undefined target"
2133446Smrj#endif
2143446Smrj
2153446Smrj	.code32
2163446Smrj
2173446Smrj	/*
2183446Smrj	 * if reset fails halt the system
2193446Smrj	 */
2203446Smrj	ENTRY_NP(dboot_halt)
2213446Smrj	hlt
2223446Smrj	SET_SIZE(dboot_halt)
2233446Smrj
2243446Smrj	/*
2253446Smrj	 * flush the TLB
2263446Smrj	 */
2273446Smrj	ENTRY_NP(reload_cr3)
2283446Smrj	movl	%cr3, %eax
2293446Smrj	movl	%eax, %cr3
2303446Smrj	ret
2313446Smrj	SET_SIZE(reload_cr3)
2323446Smrj
2333446Smrj	/*
2343446Smrj	 * Detect if we can do cpuid, see if we can change bit 21 of eflags.
2353446Smrj	 * Note we don't do the bizarre tests for Cyrix CPUs in ml/locore.s.
2363446Smrj	 * If you're on such a CPU, you're stuck with non-PAE 32 bit kernels.
2373446Smrj	 */
2383446Smrj	ENTRY_NP(have_cpuid)
2393446Smrj	pushf
2403446Smrj	pushf
2413446Smrj	xorl	%eax, %eax
2423446Smrj	popl	%ecx
2433446Smrj	movl	%ecx, %edx
2443446Smrj	xorl	$0x200000, %ecx
2453446Smrj	pushl	%ecx
2463446Smrj	popf
2473446Smrj	pushf
2483446Smrj	popl	%ecx
2493446Smrj	cmpl	%ecx, %edx
2503446Smrj	setne	%al
2513446Smrj	popf
2523446Smrj	ret
2533446Smrj	SET_SIZE(have_cpuid)
2543446Smrj
2555460Sjosephb	/*
2565460Sjosephb	 * We want the GDT to be on its own page for better performance
2575460Sjosephb	 * running under hypervisors.
2585460Sjosephb	 */
2595460Sjosephb	.skip 4096
2603446Smrj#include "../boot/boot_gdt.s"
2615460Sjosephb	.skip 4096
2625460Sjosephb	.long	0
2633446Smrj
2643446Smrj#endif /* __lint */
265