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