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