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 #include <sys/multiboot.h> 28 #include <sys/multiboot2.h> 29 #include <sys/asm_linkage.h> 30 #include <sys/segments.h> 31 #include <sys/controlregs.h> 32 33 #include "dboot_xboot.h" 34 35 .text 36 .globl _start 37 _start: 38 jmp code_start 39 40 /* 41 * The multiboot header has to be at the start of the file 42 * 43 * The 32 bit kernel is ELF32, so the MB header is mostly ignored. 44 * 45 * The 64 bit kernel is ELF64, so we get grub to load the entire 46 * ELF file into memory and trick it into jumping into this code. 47 * The trick is done by a binary utility run after unix is linked, 48 * that rewrites the mb_header. 49 */ 50 .align 4 51 .globl mb_header 52 mb_header: 53 .long MB_HEADER_MAGIC /* magic number */ 54 #if defined(_BOOT_TARGET_i386) 55 .long MB_HEADER_FLAGS_32 /* flags */ 56 .long MB_HEADER_CHECKSUM_32 /* checksum */ 57 #elif defined (_BOOT_TARGET_amd64) 58 .long MB_HEADER_FLAGS_64 /* flags */ 59 .long MB_HEADER_CHECKSUM_64 /* checksum */ 60 #else 61 #error No architecture defined 62 #endif 63 .long 0x11111111 /* header_addr: patched by mbh_patch */ 64 .long 0x100000 /* load_addr: patched by mbh_patch */ 65 .long 0 /* load_end_addr - 0 means entire file */ 66 .long 0 /* bss_end_addr */ 67 .long 0x2222222 /* entry_addr: patched by mbh_patch */ 68 .long 0 /* video mode.. */ 69 .long 0 /* width 0 == don't care */ 70 .long 0 /* height 0 == don't care */ 71 .long 0 /* depth 0 == don't care */ 72 73 #if defined(_BOOT_TARGET_i386) 74 /* 75 * The MB2 header must be 8 byte aligned relative to the beginning of 76 * the in-memory ELF object. The 32-bit kernel ELF file has sections 77 * which are 4-byte aligned, and as .align family directives only do 78 * control the alignment inside the section, we need to construct the 79 * image manually, by inserting the padding where needed. The alignment 80 * setup here depends on the first PT_LOAD section of the ELF file, if 81 * this section offset will change, this code must be reviewed. 82 * Similarily, if we add extra tag types into the information request 83 * or add tags into the tag list. 84 */ 85 .long 0 /* padding */ 86 #else 87 .balign MULTIBOOT_HEADER_ALIGN 88 #endif 89 mb2_header: 90 .long MULTIBOOT2_HEADER_MAGIC 91 .long MULTIBOOT_ARCHITECTURE_I386 92 .long mb2_header_end - mb2_header 93 .long -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE_I386 + (mb2_header_end - mb2_header)) 94 95 /* 96 * Multiboot 2 tags follow. Note, the first tag immediately follows 97 * the header. Subsequent tags must be aligned by MULTIBOOT_TAG_ALIGN. 98 * 99 * MB information request tag. 100 */ 101 information_request_tag_start: 102 .word MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 103 .word 0 104 .long information_request_tag_end - information_request_tag_start 105 .long MULTIBOOT_TAG_TYPE_CMDLINE 106 .long MULTIBOOT_TAG_TYPE_MODULE 107 .long MULTIBOOT_TAG_TYPE_BOOTDEV 108 .long MULTIBOOT_TAG_TYPE_MMAP 109 .long MULTIBOOT_TAG_TYPE_FRAMEBUFFER 110 .long MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 111 information_request_tag_end: 112 113 #if defined (_BOOT_TARGET_amd64) 114 /* 115 * The following values are patched by mbh_patch for the 64-bit kernel, 116 * so we only provide this tag for the 64-bit kernel. 117 */ 118 .balign MULTIBOOT_TAG_ALIGN 119 address_tag_start: 120 .word MULTIBOOT_HEADER_TAG_ADDRESS 121 .word 0 122 .long address_tag_end - address_tag_start 123 .long mb2_header 124 .globl mb2_load_addr 125 mb2_load_addr: 126 .long 0 /* load addr */ 127 .long 0 /* load_end_addr */ 128 .long 0 /* bss_end_addr */ 129 address_tag_end: 130 /* 131 * entry address tag 132 */ 133 .balign MULTIBOOT_TAG_ALIGN 134 entry_address_tag_start: 135 .word MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 136 .word 0 137 .long entry_address_tag_end - entry_address_tag_start 138 .long 0 /* entry addr */ 139 entry_address_tag_end: 140 141 .balign MULTIBOOT_TAG_ALIGN /* Alignment for the next tag */ 142 #endif 143 /* 144 * MB console flags tag 145 */ 146 console_tag_start: 147 .word MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 148 .word 0 149 .long console_tag_end - console_tag_start 150 .long MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 151 console_tag_end: 152 .long 0 /* padding */ 153 154 /* 155 * MB header framebuffer tag 156 */ 157 framebuffer_tag_start: 158 .word MULTIBOOT_HEADER_TAG_FRAMEBUFFER 159 .word 0 160 .long framebuffer_tag_end - framebuffer_tag_start 161 .long 0 /* width - no preference */ 162 .long 0 /* height - no preference */ 163 .long 0 /* depth - no preference */ 164 framebuffer_tag_end: 165 .long 0 /* padding */ 166 167 /* 168 * Tell the bootloader to load the modules page aligned to 169 * the specified alignment. 170 */ 171 .word MULTIBOOT_HEADER_TAG_MODULE_ALIGN 172 .word 0 173 .long 8 174 175 /* 176 * Termination tag. 177 */ 178 .word MULTIBOOT_HEADER_TAG_END 179 .word 0 180 .long 8 181 mb2_header_end: 182 183 /* 184 * At entry we are in protected mode, 32 bit execution, paging and 185 * interrupts are disabled. 186 * 187 * EAX == MB_BOOTLOADER_MAGIC 188 * EBX points to multiboot information 189 * segment registers all have segments with base 0, limit == 0xffffffff 190 */ 191 code_start: 192 movl %eax, mb_magic 193 movl %ebx, mb_addr 194 195 movl $stack_space, %esp /* load my stack pointer */ 196 addl $STACK_SIZE, %esp 197 198 pushl $0x0 /* push a dead-end frame */ 199 pushl $0x0 200 movl %esp, %ebp 201 202 pushl $0x0 /* clear all processor flags */ 203 popf 204 205 /* 206 * setup a global descriptor table with known contents 207 */ 208 lgdt gdt_info 209 movw $B32DATA_SEL, %ax 210 movw %ax, %ds 211 movw %ax, %es 212 movw %ax, %fs 213 movw %ax, %gs 214 movw %ax, %ss 215 ljmp $B32CODE_SEL, $newgdt 216 newgdt: 217 nop 218 219 /* 220 * go off and determine memory config, build page tables, etc. 221 */ 222 call startup_kernel 223 224 225 /* 226 * On amd64 we'll want the stack pointer to be 16 byte aligned. 227 */ 228 andl $0xfffffff0, %esp 229 230 /* 231 * Enable PGE, PAE and large pages 232 */ 233 movl %cr4, %eax 234 testl $1, pge_support 235 jz 1f 236 orl $CR4_PGE, %eax 237 1: 238 testl $1, pae_support 239 jz 1f 240 orl $CR4_PAE, %eax 241 1: 242 testl $1, largepage_support 243 jz 1f 244 orl $CR4_PSE, %eax 245 1: 246 movl %eax, %cr4 247 248 /* 249 * enable NX protection if processor supports it 250 */ 251 testl $1, NX_support 252 jz 1f 253 movl $MSR_AMD_EFER, %ecx 254 rdmsr 255 orl $AMD_EFER_NXE, %eax 256 wrmsr 257 1: 258 259 260 /* 261 * load the pagetable base address into cr3 262 */ 263 movl top_page_table, %eax 264 movl %eax, %cr3 265 266 #if defined(_BOOT_TARGET_amd64) 267 /* 268 * enable long mode 269 */ 270 movl $MSR_AMD_EFER, %ecx 271 rdmsr 272 orl $AMD_EFER_LME, %eax 273 wrmsr 274 #endif 275 276 /* 277 * enable paging, write protection, alignment masking, but disable 278 * the cache disable and write through only bits. 279 */ 280 movl %cr0, %eax 281 orl $_CONST(CR0_PG | CR0_WP | CR0_AM), %eax 282 andl $_BITNOT(CR0_NW | CR0_CD), %eax 283 movl %eax, %cr0 284 jmp paging_on 285 paging_on: 286 287 /* 288 * The xboot_info ptr gets passed to the kernel as its argument 289 */ 290 movl bi, %edi 291 movl entry_addr_low, %esi 292 293 #if defined(_BOOT_TARGET_i386) 294 295 pushl %edi 296 call *%esi 297 298 #elif defined(_BOOT_TARGET_amd64) 299 300 /* 301 * We're still in compatibility mode with 32 bit execution. 302 * Switch to 64 bit mode now by switching to a 64 bit code segment. 303 * then set up and do a lret to get into 64 bit execution. 304 */ 305 pushl $B64CODE_SEL 306 pushl $longmode 307 lret 308 longmode: 309 .code64 310 movq $0xffffffff00000000,%rdx 311 orq %rdx, %rsi /* set upper bits of entry addr */ 312 notq %rdx 313 andq %rdx, %rdi /* clean %rdi for passing arg */ 314 call *%rsi 315 316 #else 317 #error "undefined target" 318 #endif 319 320 .code32 321 322 /* 323 * if reset fails halt the system 324 */ 325 ENTRY_NP(dboot_halt) 326 hlt 327 SET_SIZE(dboot_halt) 328 329 /* 330 * flush the TLB 331 */ 332 ENTRY_NP(reload_cr3) 333 movl %cr3, %eax 334 movl %eax, %cr3 335 ret 336 SET_SIZE(reload_cr3) 337 338 /* 339 * Detect if we can do cpuid, see if we can change bit 21 of eflags. 340 * Note we don't do the bizarre tests for Cyrix CPUs in ml/locore.s. 341 * If you're on such a CPU, you're stuck with non-PAE 32 bit kernels. 342 */ 343 ENTRY_NP(have_cpuid) 344 pushf 345 pushf 346 xorl %eax, %eax 347 popl %ecx 348 movl %ecx, %edx 349 xorl $0x200000, %ecx 350 pushl %ecx 351 popf 352 pushf 353 popl %ecx 354 cmpl %ecx, %edx 355 setne %al 356 popf 357 ret 358 SET_SIZE(have_cpuid) 359 360 /* 361 * We want the GDT to be on its own page for better performance 362 * running under hypervisors. 363 */ 364 .skip 4096 365 #include "../boot/boot_gdt.s" 366 .skip 4096 367 .long 0 368