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 29 int 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 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 #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 95 mb2_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 */ 107 information_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_FRAMEBUFFER 116 .long MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 117 information_request_tag_end: 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 125 address_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 131 mb2_load_addr: 132 .long 0 /* load addr */ 133 .long 0 /* load_end_addr */ 134 .long 0 /* bss_end_addr */ 135 address_tag_end: 136 /* 137 * entry address tag 138 */ 139 .balign MULTIBOOT_TAG_ALIGN 140 entry_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 */ 145 entry_address_tag_end: 146 147 .balign MULTIBOOT_TAG_ALIGN /* Alignment for the next tag */ 148 #endif 149 /* 150 * MB console flags tag 151 */ 152 console_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 157 console_tag_end: 158 .long 0 /* padding */ 159 160 /* 161 * MB header framebuffer tag 162 */ 163 framebuffer_tag_start: 164 .word MULTIBOOT_HEADER_TAG_FRAMEBUFFER 165 .word 0 166 .long framebuffer_tag_end - framebuffer_tag_start 167 .long 0 /* width - no preference */ 168 .long 0 /* height - no preference */ 169 .long 0 /* depth - no preference */ 170 framebuffer_tag_end: 171 .long 0 /* padding */ 172 173 /* 174 * Tell the bootloader to load the modules page aligned to 175 * the specified alignment. 176 */ 177 .word MULTIBOOT_HEADER_TAG_MODULE_ALIGN 178 .word 0 179 .long 8 180 181 /* 182 * Termination tag. 183 */ 184 .word MULTIBOOT_HEADER_TAG_END 185 .word 0 186 .long 8 187 mb2_header_end: 188 189 /* 190 * At entry we are in protected mode, 32 bit execution, paging and 191 * interrupts are disabled. 192 * 193 * EAX == MB_BOOTLOADER_MAGIC 194 * EBX points to multiboot information 195 * segment registers all have segments with base 0, limit == 0xffffffff 196 */ 197 code_start: 198 movl %eax, mb_magic 199 movl %ebx, mb_addr 200 201 movl $stack_space, %esp /* load my stack pointer */ 202 addl $STACK_SIZE, %esp 203 204 pushl $0x0 /* push a dead-end frame */ 205 pushl $0x0 206 movl %esp, %ebp 207 208 pushl $0x0 /* clear all processor flags */ 209 popf 210 211 /* 212 * setup a global descriptor table with known contents 213 */ 214 lgdt gdt_info 215 movw $B32DATA_SEL, %ax 216 movw %ax, %ds 217 movw %ax, %es 218 movw %ax, %fs 219 movw %ax, %gs 220 movw %ax, %ss 221 ljmp $B32CODE_SEL, $newgdt 222 newgdt: 223 nop 224 225 /* 226 * go off and determine memory config, build page tables, etc. 227 */ 228 call startup_kernel 229 230 231 /* 232 * On amd64 we'll want the stack pointer to be 16 byte aligned. 233 */ 234 andl $0xfffffff0, %esp 235 236 /* 237 * Enable PGE, PAE and large pages 238 */ 239 movl %cr4, %eax 240 testl $1, pge_support 241 jz 1f 242 orl $CR4_PGE, %eax 243 1: 244 testl $1, pae_support 245 jz 1f 246 orl $CR4_PAE, %eax 247 1: 248 testl $1, largepage_support 249 jz 1f 250 orl $CR4_PSE, %eax 251 1: 252 movl %eax, %cr4 253 254 /* 255 * enable NX protection if processor supports it 256 */ 257 testl $1, NX_support 258 jz 1f 259 movl $MSR_AMD_EFER, %ecx 260 rdmsr 261 orl $AMD_EFER_NXE, %eax 262 wrmsr 263 1: 264 265 266 /* 267 * load the pagetable base address into cr3 268 */ 269 movl top_page_table, %eax 270 movl %eax, %cr3 271 272 #if defined(_BOOT_TARGET_amd64) 273 /* 274 * enable long mode 275 */ 276 movl $MSR_AMD_EFER, %ecx 277 rdmsr 278 orl $AMD_EFER_LME, %eax 279 wrmsr 280 #endif 281 282 /* 283 * enable paging, write protection, alignment masking, but disable 284 * the cache disable and write through only bits. 285 */ 286 movl %cr0, %eax 287 orl $_CONST(CR0_PG | CR0_WP | CR0_AM), %eax 288 andl $_BITNOT(CR0_NW | CR0_CD), %eax 289 movl %eax, %cr0 290 jmp paging_on 291 paging_on: 292 293 /* 294 * The xboot_info ptr gets passed to the kernel as its argument 295 */ 296 movl bi, %edi 297 movl entry_addr_low, %esi 298 299 #if defined(_BOOT_TARGET_i386) 300 301 pushl %edi 302 call *%esi 303 304 #elif defined(_BOOT_TARGET_amd64) 305 306 /* 307 * We're still in compatibility mode with 32 bit execution. 308 * Switch to 64 bit mode now by switching to a 64 bit code segment. 309 * then set up and do a lret to get into 64 bit execution. 310 */ 311 pushl $B64CODE_SEL 312 pushl $longmode 313 lret 314 longmode: 315 .code64 316 movq $0xffffffff00000000,%rdx 317 orq %rdx, %rsi /* set upper bits of entry addr */ 318 notq %rdx 319 andq %rdx, %rdi /* clean %rdi for passing arg */ 320 call *%rsi 321 322 #else 323 #error "undefined target" 324 #endif 325 326 .code32 327 328 /* 329 * if reset fails halt the system 330 */ 331 ENTRY_NP(dboot_halt) 332 hlt 333 SET_SIZE(dboot_halt) 334 335 /* 336 * flush the TLB 337 */ 338 ENTRY_NP(reload_cr3) 339 movl %cr3, %eax 340 movl %eax, %cr3 341 ret 342 SET_SIZE(reload_cr3) 343 344 /* 345 * Detect if we can do cpuid, see if we can change bit 21 of eflags. 346 * Note we don't do the bizarre tests for Cyrix CPUs in ml/locore.s. 347 * If you're on such a CPU, you're stuck with non-PAE 32 bit kernels. 348 */ 349 ENTRY_NP(have_cpuid) 350 pushf 351 pushf 352 xorl %eax, %eax 353 popl %ecx 354 movl %ecx, %edx 355 xorl $0x200000, %ecx 356 pushl %ecx 357 popf 358 pushf 359 popl %ecx 360 cmpl %ecx, %edx 361 setne %al 362 popf 363 ret 364 SET_SIZE(have_cpuid) 365 366 /* 367 * We want the GDT to be on its own page for better performance 368 * running under hypervisors. 369 */ 370 .skip 4096 371 #include "../boot/boot_gdt.s" 372 .skip 4096 373 .long 0 374 375 #endif /* __lint */