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