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