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 2008 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28#if defined(__lint) 29 30int 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 58mb_header: 59 .long MB_HEADER_MAGIC /* magic number */ 60 .long MB_HEADER_FLAGS /* flags */ 61 .long MB_HEADER_CHECKSUM /* checksum */ 62 .long 0x11111111 /* header_addr: patched by elfpatch */ 63 .long 0x100000 /* load_addr: patched by elfpatch */ 64 .long 0 /* load_end_addr - 0 means entire file */ 65 .long 0 /* bss_end_addr */ 66 .long 0x2222222 /* entry_addr: patched by elfpatch */ 67 .long 0 /* video mode.. */ 68 .long 0 /* width 0 == don't care */ 69 .long 0 /* height 0 == don't care */ 70 .long 0 /* depth 0 == don't care */ 71 72 /* 73 * At entry we are in protected mode, 32 bit execution, paging and 74 * interrupts are disabled. 75 * 76 * EAX == MB_BOOTLOADER_MAGIC 77 * EBX points to multiboot information 78 * segment registers all have segments with base 0, limit == 0xffffffff 79 */ 80code_start: 81 movl %ebx, mb_info 82 83 movl $stack_space, %esp /* load my stack pointer */ 84 addl $STACK_SIZE, %esp 85 86 pushl $0x0 /* push a dead-end frame */ 87 pushl $0x0 88 movl %esp, %ebp 89 90 pushl $0x0 /* clear all processor flags */ 91 popf 92 93 /* 94 * setup a global descriptor table with known contents 95 */ 96 lgdt gdt_info 97 movw $B32DATA_SEL, %ax 98 movw %ax, %ds 99 movw %ax, %es 100 movw %ax, %fs 101 movw %ax, %gs 102 movw %ax, %ss 103 ljmp $B32CODE_SEL, $newgdt 104newgdt: 105 nop 106 107 /* 108 * go off and determine memory config, build page tables, etc. 109 */ 110 call startup_kernel 111 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, write protection, alignment masking, but disable 166 * the cache disable and write through only bits. 167 */ 168 movl %cr0, %eax 169 orl $_CONST(CR0_PG | CR0_WP | CR0_AM), %eax 170 andl $_BITNOT(CR0_NW | CR0_CD), %eax 171 movl %eax, %cr0 172 jmp paging_on 173paging_on: 174 175 /* 176 * The xboot_info ptr gets passed to the kernel as its argument 177 */ 178 movl bi, %edi 179 movl entry_addr_low, %esi 180 181#if defined(_BOOT_TARGET_i386) 182 183 pushl %edi 184 call *%esi 185 186#elif defined(_BOOT_TARGET_amd64) 187 188 /* 189 * We're still in compatibility mode with 32 bit execution. 190 * Switch to 64 bit mode now by switching to a 64 bit code segment. 191 * then set up and do a lret to get into 64 bit execution. 192 */ 193 pushl $B64CODE_SEL 194 pushl $longmode 195 lret 196longmode: 197 .code64 198 movq $0xffffffff00000000,%rdx 199 orq %rdx, %rsi /* set upper bits of entry addr */ 200 notq %rdx 201 andq %rdx, %rdi /* clean %rdi for passing arg */ 202 call *%rsi 203 204#else 205#error "undefined target" 206#endif 207 208 .code32 209 210 /* 211 * if reset fails halt the system 212 */ 213 ENTRY_NP(dboot_halt) 214 hlt 215 SET_SIZE(dboot_halt) 216 217 /* 218 * flush the TLB 219 */ 220 ENTRY_NP(reload_cr3) 221 movl %cr3, %eax 222 movl %eax, %cr3 223 ret 224 SET_SIZE(reload_cr3) 225 226 /* 227 * Detect if we can do cpuid, see if we can change bit 21 of eflags. 228 * Note we don't do the bizarre tests for Cyrix CPUs in ml/locore.s. 229 * If you're on such a CPU, you're stuck with non-PAE 32 bit kernels. 230 */ 231 ENTRY_NP(have_cpuid) 232 pushf 233 pushf 234 xorl %eax, %eax 235 popl %ecx 236 movl %ecx, %edx 237 xorl $0x200000, %ecx 238 pushl %ecx 239 popf 240 pushf 241 popl %ecx 242 cmpl %ecx, %edx 243 setne %al 244 popf 245 ret 246 SET_SIZE(have_cpuid) 247 248 /* 249 * We want the GDT to be on its own page for better performance 250 * running under hypervisors. 251 */ 252 .skip 4096 253#include "../boot/boot_gdt.s" 254 .skip 4096 255 .long 0 256 257#endif /* __lint */ 258