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*e84622caSToomas 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*e84622caSToomas Soome#if defined(_BOOT_TARGET_i386) 80*e84622caSToomas Soome /* 81*e84622caSToomas Soome * The MB2 header must be 8 byte aligned relative to the beginning of 82*e84622caSToomas Soome * the in-memory ELF object. The 32-bit kernel ELF file has sections 83*e84622caSToomas Soome * which are 4-byte aligned, and as .align family directives only do 84*e84622caSToomas Soome * control the alignment inside the section, we need to construct the 85*e84622caSToomas Soome * image manually, by inserting the padding where needed. The alignment 86*e84622caSToomas Soome * setup here depends on the first PT_LOAD section of the ELF file, if 87*e84622caSToomas Soome * this section offset will change, this code must be reviewed. 88*e84622caSToomas Soome * Similarily, if we add extra tag types into the information request 89*e84622caSToomas Soome * or add tags into the tag list. 90*e84622caSToomas Soome */ 91*e84622caSToomas Soome .long 0 /* padding */ 92*e84622caSToomas Soome#else 93*e84622caSToomas Soome .balign MULTIBOOT_HEADER_ALIGN 94*e84622caSToomas Soome#endif 95*e84622caSToomas Soomemb2_header: 96*e84622caSToomas Soome .long MULTIBOOT2_HEADER_MAGIC 97*e84622caSToomas Soome .long MULTIBOOT_ARCHITECTURE_I386 98*e84622caSToomas Soome .long mb2_header_end - mb2_header 99*e84622caSToomas Soome .long -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE_I386 + (mb2_header_end - mb2_header)) 100*e84622caSToomas Soome 101*e84622caSToomas Soome /* 102*e84622caSToomas Soome * Multiboot 2 tags follow. Note, the first tag immediately follows 103*e84622caSToomas Soome * the header. Subsequent tags must be aligned by MULTIBOOT_TAG_ALIGN. 104*e84622caSToomas Soome * 105*e84622caSToomas Soome * MB information request tag. 106*e84622caSToomas Soome */ 107*e84622caSToomas Soomeinformation_request_tag_start: 108*e84622caSToomas Soome .word MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 109*e84622caSToomas Soome .word 0 110*e84622caSToomas Soome .long information_request_tag_end - information_request_tag_start 111*e84622caSToomas Soome .long MULTIBOOT_TAG_TYPE_CMDLINE 112*e84622caSToomas Soome .long MULTIBOOT_TAG_TYPE_MODULE 113*e84622caSToomas Soome .long MULTIBOOT_TAG_TYPE_BOOTDEV 114*e84622caSToomas Soome .long MULTIBOOT_TAG_TYPE_MMAP 115*e84622caSToomas Soome .long MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 116*e84622caSToomas Soomeinformation_request_tag_end: 117*e84622caSToomas Soome .long 0 /* padding */ 118*e84622caSToomas Soome 119*e84622caSToomas Soome#if defined (_BOOT_TARGET_amd64) 120*e84622caSToomas Soome /* 121*e84622caSToomas Soome * The following values are patched by mbh_patch for the 64-bit kernel, 122*e84622caSToomas Soome * so we only provide this tag for the 64-bit kernel. 123*e84622caSToomas Soome */ 124*e84622caSToomas Soome .balign MULTIBOOT_TAG_ALIGN 125*e84622caSToomas Soomeaddress_tag_start: 126*e84622caSToomas Soome .word MULTIBOOT_HEADER_TAG_ADDRESS 127*e84622caSToomas Soome .word 0 128*e84622caSToomas Soome .long address_tag_end - address_tag_start 129*e84622caSToomas Soome .long mb2_header 130*e84622caSToomas Soome .globl mb2_load_addr 131*e84622caSToomas Soomemb2_load_addr: 132*e84622caSToomas Soome .long 0 /* load addr */ 133*e84622caSToomas Soome .long 0 /* load_end_addr */ 134*e84622caSToomas Soome .long 0 /* bss_end_addr */ 135*e84622caSToomas Soomeaddress_tag_end: 136*e84622caSToomas Soome /* 137*e84622caSToomas Soome * entry address tag 138*e84622caSToomas Soome */ 139*e84622caSToomas Soome .balign MULTIBOOT_TAG_ALIGN 140*e84622caSToomas Soomeentry_address_tag_start: 141*e84622caSToomas Soome .word MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 142*e84622caSToomas Soome .word 0 143*e84622caSToomas Soome .long entry_address_tag_end - entry_address_tag_start 144*e84622caSToomas Soome .long 0 /* entry addr */ 145*e84622caSToomas Soomeentry_address_tag_end: 146*e84622caSToomas Soome 147*e84622caSToomas Soome .balign MULTIBOOT_TAG_ALIGN /* Alignment for the next tag */ 148*e84622caSToomas Soome#endif 149*e84622caSToomas Soome /* 150*e84622caSToomas Soome * MB console flags tag 151*e84622caSToomas Soome */ 152*e84622caSToomas Soomeconsole_tag_start: 153*e84622caSToomas Soome .word MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 154*e84622caSToomas Soome .word 0 155*e84622caSToomas Soome .long console_tag_end - console_tag_start 156*e84622caSToomas Soome .long MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 157*e84622caSToomas Soomeconsole_tag_end: 158*e84622caSToomas Soome .long 0 /* padding */ 159*e84622caSToomas Soome 160*e84622caSToomas Soome /* 161*e84622caSToomas Soome * Tell the bootloader to load the modules page aligned to 162*e84622caSToomas Soome * the specified alignment. 163*e84622caSToomas Soome */ 164*e84622caSToomas Soome .word MULTIBOOT_HEADER_TAG_MODULE_ALIGN 165*e84622caSToomas Soome .word 0 166*e84622caSToomas Soome .long 8 167*e84622caSToomas Soome 168*e84622caSToomas Soome /* 169*e84622caSToomas Soome * Termination tag. 170*e84622caSToomas Soome */ 171*e84622caSToomas Soome .word MULTIBOOT_HEADER_TAG_END 172*e84622caSToomas Soome .word 0 173*e84622caSToomas Soome .long 8 174*e84622caSToomas Soomemb2_header_end: 175*e84622caSToomas 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*e84622caSToomas Soome movl %eax, mb_magic 186*e84622caSToomas 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