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 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 
  28 #if defined(__lint)
  29 
  30 int fb_swtch_silence_lint = 0;
  31 
  32 #else
  33 
  34 #include <sys/asm_linkage.h>
  35 #include <sys/segments.h>
  36 #include <sys/controlregs.h>
  37 #include <sys/machparam.h>
  38 #include <sys/multiboot.h>
  39 #include <sys/fastboot.h>
  40 #include "assym.h"
  41 
  42 /*
  43  * This code is to switch from 64-bit or 32-bit to protected mode.
  44  */
  45 
  46 /*
  47  * For debugging with LEDs
  48  */
  49 #define FB_OUTB_ASM(val)        \
  50     movb        val, %al;       \
  51     outb        $0x80;
  52 
  53 
  54 #define DISABLE_PAGING                                                  \
  55         movl    %cr0, %eax                                              ;\
  56         btrl    $31, %eax       /* clear PG bit */                      ;\
  57         movl    %eax, %cr0
  58 
  59 /*
  60  * This macro contains common code for 64/32-bit versions of copy_sections().
  61  * On entry:
  62  *      fbf points to the fboot_file_t
  63  *      snum contains the number of sections
  64  * Registers that would be clobbered:
  65  *      fbs, snum, %eax, %ecx, %edi, %esi.
  66  * NOTE: fb_dest_pa is supposed to be in the first 1GB,
  67  * therefore it is safe to use 32-bit register to hold it's value
  68  * even for 64-bit code.
  69  */
  70 
  71 #define COPY_SECT(fbf, fbs, snum)               \
  72         lea     FB_SECTIONS(fbf), fbs;          \
  73         xorl    %eax, %eax;                     \
  74 1:      movl    FB_DEST_PA(fbf), %esi;          \
  75         addl    FB_SEC_OFFSET(fbs), %esi;       \
  76         movl    FB_SEC_PADDR(fbs), %edi;        \
  77         movl    FB_SEC_SIZE(fbs), %ecx;         \
  78         rep                                     \
  79           movsb;                                \
  80         /* Zero BSS */                          \
  81         movl    FB_SEC_BSS_SIZE(fbs), %ecx;     \
  82         rep                                     \
  83           stosb;                                \
  84         add     $FB_SECTIONS_INCR, fbs;         \
  85         dec     snum;                           \
  86         jnz     1b
  87 
  88 
  89         .globl  _start
  90 _start:
  91 
  92         /* Disable interrupts */
  93         cli
  94 
  95 #if defined(__amd64)
  96         /* Switch to a low memory stack */
  97         movq    $_start, %rsp
  98         addq    $FASTBOOT_STACK_OFFSET, %rsp
  99 
 100         /*
 101          * Copy from old stack to new stack
 102          * If the content before fi_valid gets bigger than 0x200 bytes,
 103          * the reserved stack size above will need to be changed.
 104          */
 105         movq    %rdi, %rsi      /* source from old stack */
 106         movq    %rsp, %rdi      /* destination on the new stack */
 107         movq    $FI_VALID, %rcx /* size to copy */
 108         rep
 109           smovb
 110 
 111 #elif defined(__i386)
 112         movl    0x4(%esp), %esi /* address of fastboot info struct */
 113 
 114         /* Switch to a low memory stack */
 115         movl    $_start, %esp
 116         addl    $FASTBOOT_STACK_OFFSET, %esp
 117 
 118         /* Copy struct to stack */
 119         movl    %esp, %edi      /* destination on the new stack */
 120         movl    $FI_VALID, %ecx /* size to copy */
 121         rep
 122           smovb
 123 
 124 #endif
 125 
 126 #if defined(__amd64)
 127 
 128         xorl    %eax, %eax
 129         xorl    %edx, %edx
 130 
 131         movl    $MSR_AMD_FSBASE, %ecx
 132         wrmsr
 133 
 134         movl    $MSR_AMD_GSBASE, %ecx
 135         wrmsr
 136 
 137         movl    $MSR_AMD_KGSBASE, %ecx
 138         wrmsr
 139 
 140 #endif
 141         /*
 142          * zero out all the registers to make sure they're 16 bit clean
 143          */
 144 #if defined(__amd64)
 145         xorq    %r8, %r8
 146         xorq    %r9, %r9
 147         xorq    %r10, %r10
 148         xorq    %r11, %r11
 149         xorq    %r12, %r12
 150         xorq    %r13, %r13
 151         xorq    %r14, %r14
 152         xorq    %r15, %r15
 153 #endif
 154         xorl    %eax, %eax
 155         xorl    %ebx, %ebx
 156         xorl    %ecx, %ecx
 157         xorl    %edx, %edx
 158         xorl    %ebp, %ebp
 159 
 160 #if defined(__amd64)
 161         /*
 162          * Load our own GDT
 163          */
 164         lgdt    gdt_info
 165 #endif
 166         /*
 167          * Load our own IDT
 168          */
 169         lidt    idt_info
 170 
 171 #if defined(__amd64)
 172         /*
 173          * Invalidate all TLB entries.
 174          * Load temporary pagetables to copy kernel and boot-archive
 175          */
 176         movq    %cr4, %rax
 177         andq    $_BITNOT(CR4_PGE), %rax
 178         movq    %rax, %cr4
 179         movq    FI_PAGETABLE_PA(%rsp), %rax
 180         movq    %rax, %cr3
 181 
 182         leaq    FI_FILES(%rsp), %rbx    /* offset to the files */
 183 
 184         /* copy unix to final destination */
 185         movq    FI_LAST_TABLE_PA(%rsp), %rsi    /* page table PA */
 186         leaq    _MUL(FASTBOOT_UNIX, FI_FILES_INCR)(%rbx), %rdi
 187         call    map_copy
 188 
 189         /* copy boot archive to final destination */
 190         movq    FI_LAST_TABLE_PA(%rsp), %rsi    /* page table PA */
 191         leaq    _MUL(FASTBOOT_BOOTARCHIVE, FI_FILES_INCR)(%rbx), %rdi
 192         call    map_copy
 193 
 194         /* Copy sections if there are any */ 
 195         leaq    _MUL(FASTBOOT_UNIX, FI_FILES_INCR)(%rbx), %rdi
 196         movl    FB_SECTCNT(%rdi), %esi
 197         cmpl    $0, %esi
 198         je      1f
 199         call    copy_sections
 200 1:
 201         /*
 202          * Shut down 64 bit mode. First get into compatiblity mode.
 203          */
 204         movq    %rsp, %rax
 205         pushq   $B32DATA_SEL
 206         pushq   %rax
 207         pushf
 208         pushq   $B32CODE_SEL
 209         pushq   $1f
 210         iretq
 211 
 212         .code32
 213 1:
 214         movl    $B32DATA_SEL, %eax
 215         movw    %ax, %ss
 216         movw    %ax, %ds
 217         movw    %ax, %es
 218         movw    %ax, %fs
 219         movw    %ax, %gs
 220 
 221         /*
 222          * Disable long mode by:
 223          * - shutting down paging (bit 31 of cr0).  This will flush the
 224          *   TLBs.
 225          * - disabling LME (long mode enable) in EFER (extended feature reg)
 226          */
 227 #endif
 228         DISABLE_PAGING          /* clobbers %eax */
 229 
 230 #if defined(__amd64)
 231         ljmp    $B32CODE_SEL, $1f
 232 1:
 233 #endif
 234 
 235         /*
 236          * Clear PGE, PAE and PSE flags as dboot expects them to be
 237          * cleared.
 238          */
 239         movl    %cr4, %eax
 240         andl    $_BITNOT(CR4_PGE | CR4_PAE | CR4_PSE), %eax
 241         movl    %eax, %cr4
 242 
 243 #if defined(__amd64)
 244         movl    $MSR_AMD_EFER, %ecx     /* Extended Feature Enable */
 245         rdmsr
 246         btcl    $8, %eax                /* bit 8 Long Mode Enable bit */
 247         wrmsr
 248 
 249 #elif defined(__i386)
 250         /*
 251          * If fi_has_pae is set, re-enable paging with PAE.
 252          */
 253         leal    FI_FILES(%esp), %ebx    /* offset to the files */
 254         movl    FI_HAS_PAE(%esp), %edi  /* need to enable paging or not */
 255         cmpl    $0, %edi
 256         je      paging_on               /* no need to enable paging */
 257 
 258         movl    FI_LAST_TABLE_PA(%esp), %esi    /* page table PA */
 259 
 260         /*
 261          * Turn on PAE
 262          */
 263         movl    %cr4, %eax
 264         orl     $CR4_PAE, %eax
 265         movl    %eax, %cr4
 266 
 267         /*
 268          * Load top pagetable base address into cr3
 269          */
 270         movl    FI_PAGETABLE_PA(%esp), %eax
 271         movl    %eax, %cr3
 272 
 273         movl    %cr0, %eax
 274         orl     $_CONST(CR0_PG | CR0_WP | CR0_AM), %eax
 275         andl    $_BITNOT(CR0_NW | CR0_CD), %eax
 276         movl    %eax, %cr0
 277         jmp     paging_on
 278 paging_on:
 279 
 280         /* copy unix to final destination */
 281         leal    _MUL(FASTBOOT_UNIX, FI_FILES_INCR)(%ebx), %edx
 282         call    map_copy
 283 
 284         /* copy boot archive to final destination */
 285         leal    _MUL(FASTBOOT_BOOTARCHIVE, FI_FILES_INCR)(%ebx), %edx
 286         call    map_copy
 287 
 288         /* Disable paging one more time */
 289         DISABLE_PAGING
 290 
 291         /* Copy sections if there are any */ 
 292         leal    _MUL(FASTBOOT_UNIX, FI_FILES_INCR)(%ebx), %edx
 293         movl    FB_SECTCNT(%edx), %eax
 294         cmpl    $0, %eax
 295         je      1f
 296         call    copy_sections
 297 1:
 298 
 299         /* Whatever flags we turn on we need to turn off */
 300         movl    %cr4, %eax
 301         andl    $_BITNOT(CR4_PAE), %eax
 302         movl    %eax, %cr4
 303 #endif  /* __i386 */
 304 
 305 dboot_jump:
 306         /* Jump to dboot */
 307         movl    $DBOOT_ENTRY_ADDRESS, %edi
 308         movl    FI_NEW_MBI_PA(%esp), %ebx
 309         movl    $MB_BOOTLOADER_MAGIC, %eax
 310         jmp     *%edi
 311 
 312 #if defined(__amd64)
 313 
 314         .code64
 315         ENTRY_NP(copy_sections)
 316         /*
 317          * On entry
 318          *      %rdi points to the fboot_file_t
 319          *      %rsi contains number of sections
 320          */
 321         movq    %rdi, %rdx
 322         movq    %rsi, %r9
 323 
 324         COPY_SECT(%rdx, %r8, %r9)
 325         ret
 326         SET_SIZE(copy_sections)
 327 
 328         ENTRY_NP(map_copy)
 329         /*
 330          * On entry
 331          *      %rdi points to the fboot_file_t
 332          *      %rsi has FI_LAST_TABLE_PA(%rsp)
 333          */
 334 
 335         movq    %rdi, %rdx
 336         movq    %rsi, %r8
 337         movq    FB_PTE_LIST_PA(%rdx), %rax      /* PA list of the source */
 338         movq    FB_DEST_PA(%rdx), %rdi          /* PA of the destination */
 339 
 340 2:
 341         movq    (%rax), %rcx                    /* Are we done? */
 342         cmpl    $FASTBOOT_TERMINATE, %ecx
 343         je      1f
 344 
 345         movq    %rcx, (%r8)
 346         movq    %cr3, %rsi              /* Reload cr3 */
 347         movq    %rsi, %cr3
 348         movq    FB_VA(%rdx), %rsi       /* Load from VA */
 349         movq    $PAGESIZE, %rcx
 350         shrq    $3, %rcx                /* 8-byte at a time */
 351         rep
 352           smovq
 353         addq    $8, %rax                /* Go to next PTE */
 354         jmp     2b
 355 1:
 356         ret
 357         SET_SIZE(map_copy)      
 358 
 359 #elif defined(__i386)
 360 
 361         ENTRY_NP(copy_sections)
 362         /*
 363          * On entry
 364          *      %edx points to the fboot_file_t
 365          *      %eax contains the number of sections
 366          */
 367         pushl   %ebp
 368         pushl   %ebx
 369         pushl   %esi
 370         pushl   %edi
 371 
 372         movl    %eax, %ebp
 373 
 374         COPY_SECT(%edx, %ebx, %ebp)
 375 
 376         popl    %edi
 377         popl    %esi
 378         popl    %ebx
 379         popl    %ebp
 380         ret
 381         SET_SIZE(copy_sections) 
 382 
 383         ENTRY_NP(map_copy)
 384         /*
 385          * On entry
 386          *      %edx points to the fboot_file_t
 387          *      %edi has FB_HAS_PAE(%esp)
 388          *      %esi has FI_LAST_TABLE_PA(%esp)
 389          */
 390         pushl   %eax
 391         pushl   %ebx
 392         pushl   %ecx
 393         pushl   %edx
 394         pushl   %ebp
 395         pushl   %esi
 396         pushl   %edi
 397         movl    %esi, %ebp      /* Save page table PA in %ebp */
 398 
 399         movl    FB_PTE_LIST_PA(%edx), %eax      /* PA list of the source */
 400         movl    FB_DEST_PA(%edx), %ebx          /* PA of the destination */
 401 
 402 loop:
 403         movl    (%eax), %esi                    /* Are we done? */
 404         cmpl    $FASTBOOT_TERMINATE, %esi
 405         je      done
 406 
 407         cmpl    $1, (%esp)                      /* Is paging on? */
 408         jne     no_paging                       /* Nope */
 409 
 410         movl    %ebp, %edi                      /* Page table PA */
 411         movl    %esi, (%edi)                    /* Program low 32-bit */
 412         movl    4(%eax), %esi                   /* high bits of the table */
 413         movl    %esi, 4(%edi)                   /* Program high 32-bit */
 414         movl    %cr3, %esi                      /* Reload cr3 */
 415         movl    %esi, %cr3
 416         movl    FB_VA(%edx), %esi               /* Load from VA */
 417         jmp     do_copy
 418 no_paging:
 419         andl    $_BITNOT(MMU_PAGEOFFSET), %esi  /* clear lower 12-bit */
 420 do_copy:
 421         movl    %ebx, %edi
 422         movl    $PAGESIZE, %ecx
 423         shrl    $2, %ecx        /* 4-byte at a time */
 424         rep
 425           smovl
 426         addl    $8, %eax /* We built the PTEs as 8-byte entries */
 427         addl    $PAGESIZE, %ebx
 428         jmp     loop
 429 done:
 430         popl    %edi
 431         popl    %esi
 432         popl    %ebp
 433         popl    %edx
 434         popl    %ecx
 435         popl    %ebx
 436         popl    %eax
 437         ret
 438         SET_SIZE(map_copy)      
 439 #endif  /* __i386 */
 440 
 441 
 442 idt_info:
 443         .value  0x3ff
 444         .quad   0
 445 
 446 /*
 447  * We need to trampoline thru a gdt we have in low memory.
 448  */
 449 #include "../boot/boot_gdt.s"
 450 #endif /* __lint */