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 #include <sys/asm_linkage.h>
  30 #include <sys/segments.h>
  31 #include <sys/controlregs.h>
  32 #include <sys/machparam.h>
  33 #include <sys/multiboot.h>
  34 #include <sys/fastboot.h>
  35 #include "assym.h"
  36 
  37 /*
  38  * This code is to switch from 64-bit or 32-bit to protected mode.
  39  */
  40 
  41 /*
  42  * For debugging with LEDs
  43  */
  44 #define FB_OUTB_ASM(val)        \
  45     movb        val, %al;       \
  46     outb        $0x80;
  47 
  48 
  49 #define DISABLE_PAGING                                                  \
  50         movl    %cr4, %eax                                              ;\
  51         btrl    $17, %eax       /* clear PCIDE bit */                   ;\
  52         movl    %eax, %cr4                                              ;\
  53         movl    %cr0, %eax                                              ;\
  54         btrl    $31, %eax       /* clear PG bit */                      ;\
  55         movl    %eax, %cr0
  56 
  57 /*
  58  * This macro contains common code for 64/32-bit versions of copy_sections().
  59  * On entry:
  60  *      fbf points to the fboot_file_t
  61  *      snum contains the number of sections
  62  * Registers that would be clobbered:
  63  *      fbs, snum, %eax, %ecx, %edi, %esi.
  64  * NOTE: fb_dest_pa is supposed to be in the first 1GB,
  65  * therefore it is safe to use 32-bit register to hold it's value
  66  * even for 64-bit code.
  67  */
  68 
  69 #define COPY_SECT(fbf, fbs, snum)               \
  70         lea     FB_SECTIONS(fbf), fbs;          \
  71         xorl    %eax, %eax;                     \
  72 1:      movl    FB_DEST_PA(fbf), %esi;          \
  73         addl    FB_SEC_OFFSET(fbs), %esi;       \
  74         movl    FB_SEC_PADDR(fbs), %edi;        \
  75         movl    FB_SEC_SIZE(fbs), %ecx;         \
  76         rep                                     \
  77           movsb;                                \
  78         /* Zero BSS */                          \
  79         movl    FB_SEC_BSS_SIZE(fbs), %ecx;     \
  80         rep                                     \
  81           stosb;                                \
  82         add     $FB_SECTIONS_INCR, fbs;         \
  83         dec     snum;                           \
  84         jnz     1b
  85 
  86 
  87         .globl  _start
  88 _start:
  89 
  90         /* Disable interrupts */
  91         cli
  92 
  93         /* Switch to a low memory stack */
  94         movq    $_start, %rsp
  95         addq    $FASTBOOT_STACK_OFFSET, %rsp
  96 
  97         /*
  98          * Copy from old stack to new stack
  99          * If the content before fi_valid gets bigger than 0x200 bytes,
 100          * the reserved stack size above will need to be changed.
 101          */
 102         movq    %rdi, %rsi      /* source from old stack */
 103         movq    %rsp, %rdi      /* destination on the new stack */
 104         movq    $FI_VALID, %rcx /* size to copy */
 105         rep
 106           smovb
 107 
 108         xorl    %eax, %eax
 109         xorl    %edx, %edx
 110 
 111         movl    $MSR_AMD_FSBASE, %ecx
 112         wrmsr
 113 
 114         movl    $MSR_AMD_GSBASE, %ecx
 115         wrmsr
 116 
 117         movl    $MSR_AMD_KGSBASE, %ecx
 118         wrmsr
 119 
 120         /*
 121          * zero out all the registers to make sure they're 16 bit clean
 122          */
 123         xorq    %r8, %r8
 124         xorq    %r9, %r9
 125         xorq    %r10, %r10
 126         xorq    %r11, %r11
 127         xorq    %r12, %r12
 128         xorq    %r13, %r13
 129         xorq    %r14, %r14
 130         xorq    %r15, %r15
 131         xorl    %eax, %eax
 132         xorl    %ebx, %ebx
 133         xorl    %ecx, %ecx
 134         xorl    %edx, %edx
 135         xorl    %ebp, %ebp
 136 
 137         /*
 138          * Load our own GDT
 139          */
 140         lgdt    gdt_info
 141         /*
 142          * Load our own IDT
 143          */
 144         lidt    idt_info
 145 
 146         /*
 147          * Invalidate all TLB entries.
 148          * Load temporary pagetables to copy kernel and boot-archive
 149          */
 150         movq    %cr4, %rax
 151         andq    $_BITNOT(CR4_PGE), %rax
 152         movq    %rax, %cr4
 153         movq    FI_PAGETABLE_PA(%rsp), %rax
 154         movq    %rax, %cr3
 155 
 156         leaq    FI_FILES(%rsp), %rbx    /* offset to the files */
 157 
 158         /* copy unix to final destination */
 159         movq    FI_LAST_TABLE_PA(%rsp), %rsi    /* page table PA */
 160         leaq    _MUL(FASTBOOT_UNIX, FI_FILES_INCR)(%rbx), %rdi
 161         call    map_copy
 162 
 163         /* copy boot archive to final destination */
 164         movq    FI_LAST_TABLE_PA(%rsp), %rsi    /* page table PA */
 165         leaq    _MUL(FASTBOOT_BOOTARCHIVE, FI_FILES_INCR)(%rbx), %rdi
 166         call    map_copy
 167 
 168         /* Copy sections if there are any */ 
 169         leaq    _MUL(FASTBOOT_UNIX, FI_FILES_INCR)(%rbx), %rdi
 170         movl    FB_SECTCNT(%rdi), %esi
 171         cmpl    $0, %esi
 172         je      1f
 173         call    copy_sections
 174 1:
 175         /*
 176          * Shut down 64 bit mode. First get into compatiblity mode.
 177          */
 178         movq    %rsp, %rax
 179         pushq   $B32DATA_SEL
 180         pushq   %rax
 181         pushf
 182         pushq   $B32CODE_SEL
 183         pushq   $1f
 184         iretq
 185 
 186         .code32
 187 1:
 188         movl    $B32DATA_SEL, %eax
 189         movw    %ax, %ss
 190         movw    %ax, %ds
 191         movw    %ax, %es
 192         movw    %ax, %fs
 193         movw    %ax, %gs
 194 
 195         /*
 196          * Disable long mode by:
 197          * - shutting down paging (bit 31 of cr0).  This will flush the
 198          *   TLBs.
 199          * - turning off PCID in cr4
 200          * - disabling LME (long mode enable) in EFER (extended feature reg)
 201          */
 202         DISABLE_PAGING          /* clobbers %eax */
 203 
 204         ljmp    $B32CODE_SEL, $1f
 205 1:
 206 
 207         /*
 208          * Clear PGE, PAE and PSE flags as dboot expects them to be
 209          * cleared.
 210          */
 211         movl    %cr4, %eax
 212         andl    $_BITNOT(CR4_PGE | CR4_PAE | CR4_PSE), %eax
 213         movl    %eax, %cr4
 214 
 215         movl    $MSR_AMD_EFER, %ecx     /* Extended Feature Enable */
 216         rdmsr
 217         btcl    $8, %eax                /* bit 8 Long Mode Enable bit */
 218         wrmsr
 219 
 220 dboot_jump:
 221         /* Jump to dboot */
 222         movl    $DBOOT_ENTRY_ADDRESS, %edi
 223         movl    FI_NEW_MBI_PA(%esp), %ebx
 224         movl    $MB_BOOTLOADER_MAGIC, %eax
 225         jmp     *%edi
 226 
 227         .code64
 228         ENTRY_NP(copy_sections)
 229         /*
 230          * On entry
 231          *      %rdi points to the fboot_file_t
 232          *      %rsi contains number of sections
 233          */
 234         movq    %rdi, %rdx
 235         movq    %rsi, %r9
 236 
 237         COPY_SECT(%rdx, %r8, %r9)
 238         ret
 239         SET_SIZE(copy_sections)
 240 
 241         ENTRY_NP(map_copy)
 242         /*
 243          * On entry
 244          *      %rdi points to the fboot_file_t
 245          *      %rsi has FI_LAST_TABLE_PA(%rsp)
 246          */
 247 
 248         movq    %rdi, %rdx
 249         movq    %rsi, %r8
 250         movq    FB_PTE_LIST_PA(%rdx), %rax      /* PA list of the source */
 251         movq    FB_DEST_PA(%rdx), %rdi          /* PA of the destination */
 252 
 253 2:
 254         movq    (%rax), %rcx                    /* Are we done? */
 255         cmpl    $FASTBOOT_TERMINATE, %ecx
 256         je      1f
 257 
 258         movq    %rcx, (%r8)
 259         movq    %cr3, %rsi              /* Reload cr3 */
 260         movq    %rsi, %cr3
 261         movq    FB_VA(%rdx), %rsi       /* Load from VA */
 262         movq    $PAGESIZE, %rcx
 263         shrq    $3, %rcx                /* 8-byte at a time */
 264         rep
 265           smovq
 266         addq    $8, %rax                /* Go to next PTE */
 267         jmp     2b
 268 1:
 269         ret
 270         SET_SIZE(map_copy)      
 271 
 272 idt_info:
 273         .value  0x3ff
 274         .quad   0
 275 
 276 /*
 277  * We need to trampoline thru a gdt we have in low memory.
 278  */
 279 #include "../boot/boot_gdt.s"