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 */