Home | History | Annotate | Download | only in dboot
      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 2009 Sun Microsystems, Inc.  All rights reserved.
     25  * Use is subject to license terms.
     26  */
     27 
     28 #if defined(__lint)
     29 
     30 int 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
     58 mb_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 	/*
     80 	 * At entry we are in protected mode, 32 bit execution, paging and
     81 	 * interrupts are disabled.
     82 	 *
     83 	 * EAX == MB_BOOTLOADER_MAGIC
     84 	 * EBX points to multiboot information
     85 	 * segment registers all have segments with base 0, limit == 0xffffffff
     86 	 */
     87 code_start:
     88 	movl	%ebx, mb_info
     89 
     90 	movl	$stack_space, %esp	/* load my stack pointer */
     91 	addl	$STACK_SIZE, %esp
     92 
     93 	pushl	$0x0			/* push a dead-end frame */
     94 	pushl	$0x0
     95 	movl	%esp, %ebp
     96 
     97 	pushl	$0x0			/* clear all processor flags */
     98 	popf
     99 
    100 	/*
    101 	 * setup a global descriptor table with known contents
    102 	 */
    103 	lgdt	gdt_info
    104 	movw	$B32DATA_SEL, %ax
    105 	movw    %ax, %ds
    106 	movw    %ax, %es
    107 	movw    %ax, %fs
    108 	movw    %ax, %gs
    109 	movw    %ax, %ss
    110 	ljmp    $B32CODE_SEL, $newgdt
    111 newgdt:
    112 	nop
    113 
    114 	/*
    115 	 * go off and determine memory config, build page tables, etc.
    116 	 */
    117 	call	startup_kernel
    118 
    119 
    120 	/*
    121 	 * On amd64 we'll want the stack pointer to be 16 byte aligned.
    122 	 */
    123 	andl	$0xfffffff0, %esp
    124 
    125 	/*
    126 	 * Enable PGE, PAE and large pages
    127 	 */
    128 	movl	%cr4, %eax
    129 	testl	$1, pge_support
    130 	jz	1f
    131 	orl	$CR4_PGE, %eax
    132 1:
    133 	testl	$1, pae_support
    134 	jz	1f
    135 	orl	$CR4_PAE, %eax
    136 1:
    137 	testl	$1, largepage_support
    138 	jz	1f
    139 	orl	$CR4_PSE, %eax
    140 1:
    141 	movl	%eax, %cr4
    142 
    143 	/*
    144 	 * enable NX protection if processor supports it
    145 	 */
    146 	testl   $1, NX_support
    147 	jz      1f
    148 	movl    $MSR_AMD_EFER, %ecx
    149 	rdmsr
    150 	orl     $AMD_EFER_NXE, %eax
    151 	wrmsr
    152 1:
    153 
    154 
    155 	/*
    156 	 * load the pagetable base address into cr3
    157 	 */
    158 	movl	top_page_table, %eax
    159 	movl	%eax, %cr3
    160 
    161 #if defined(_BOOT_TARGET_amd64)
    162 	/*
    163 	 * enable long mode
    164 	 */
    165 	movl	$MSR_AMD_EFER, %ecx
    166 	rdmsr
    167 	orl	$AMD_EFER_LME, %eax
    168 	wrmsr
    169 #endif
    170 
    171 	/*
    172 	 * enable paging, write protection, alignment masking, but disable
    173 	 * the cache disable and write through only bits.
    174 	 */
    175 	movl	%cr0, %eax
    176 	orl	$_CONST(CR0_PG | CR0_WP | CR0_AM), %eax
    177 	andl	$_BITNOT(CR0_NW | CR0_CD), %eax
    178 	movl	%eax, %cr0
    179 	jmp	paging_on
    180 paging_on:
    181 
    182 	/*
    183 	 * The xboot_info ptr gets passed to the kernel as its argument
    184 	 */
    185 	movl	bi, %edi
    186 	movl	entry_addr_low, %esi
    187 
    188 #if defined(_BOOT_TARGET_i386)
    189 
    190 	pushl	%edi
    191 	call	*%esi
    192 
    193 #elif defined(_BOOT_TARGET_amd64)
    194 
    195 	/*
    196 	 * We're still in compatibility mode with 32 bit execution.
    197 	 * Switch to 64 bit mode now by switching to a 64 bit code segment.
    198 	 * then set up and do a lret to get into 64 bit execution.
    199 	 */
    200 	pushl	$B64CODE_SEL
    201 	pushl	$longmode
    202 	lret
    203 longmode:
    204 	.code64
    205 	movq	$0xffffffff00000000,%rdx
    206 	orq	%rdx, %rsi		/* set upper bits of entry addr */
    207 	notq	%rdx
    208 	andq	%rdx, %rdi		/* clean %rdi for passing arg */
    209 	call	*%rsi
    210 
    211 #else
    212 #error	"undefined target"
    213 #endif
    214 
    215 	.code32
    216 
    217 	/*
    218 	 * if reset fails halt the system
    219 	 */
    220 	ENTRY_NP(dboot_halt)
    221 	hlt
    222 	SET_SIZE(dboot_halt)
    223 
    224 	/*
    225 	 * flush the TLB
    226 	 */
    227 	ENTRY_NP(reload_cr3)
    228 	movl	%cr3, %eax
    229 	movl	%eax, %cr3
    230 	ret
    231 	SET_SIZE(reload_cr3)
    232 
    233 	/*
    234 	 * Detect if we can do cpuid, see if we can change bit 21 of eflags.
    235 	 * Note we don't do the bizarre tests for Cyrix CPUs in ml/locore.s.
    236 	 * If you're on such a CPU, you're stuck with non-PAE 32 bit kernels.
    237 	 */
    238 	ENTRY_NP(have_cpuid)
    239 	pushf
    240 	pushf
    241 	xorl	%eax, %eax
    242 	popl	%ecx
    243 	movl	%ecx, %edx
    244 	xorl	$0x200000, %ecx
    245 	pushl	%ecx
    246 	popf
    247 	pushf
    248 	popl	%ecx
    249 	cmpl	%ecx, %edx
    250 	setne	%al
    251 	popf
    252 	ret
    253 	SET_SIZE(have_cpuid)
    254 
    255 	/*
    256 	 * We want the GDT to be on its own page for better performance
    257 	 * running under hypervisors.
    258 	 */
    259 	.skip 4096
    260 #include "../boot/boot_gdt.s"
    261 	.skip 4096
    262 	.long	0
    263 
    264 #endif /* __lint */
    265