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.
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.
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]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2018 Joyent, Inc.
30 #include <sys/asm_linkage.h>
31 #include <sys/segments.h>
32 #include <sys/controlregs.h>
33 #include <sys/machparam.h>
34 #include <sys/multiboot.h>
35 #include <sys/fastboot.h>
39 * This code is to switch from 64-bit or 32-bit to protected mode.
43 * For debugging with LEDs
45 #define FB_OUTB_ASM(val) \
50 #define DISABLE_PAGING \
52 btrl $
17, %eax
/* clear PCIDE bit */ ;\
55 btrl $
31, %eax
/* clear PG bit */ ;\
59 * This macro contains common code for 64/32-bit versions of copy_sections().
61 * fbf points to the fboot_file_t
62 * snum contains the number of sections
63 * Registers that would be clobbered:
64 * fbs, snum, %eax, %ecx, %edi, %esi.
65 * NOTE: fb_dest_pa is supposed to be in the first 1GB,
66 * therefore it is safe to use 32-bit register to hold it's value
67 * even for 64-bit code.
70 #define COPY_SECT(fbf, fbs, snum) \
71 lea FB_SECTIONS
(fbf
), fbs; \
73 1: movl FB_DEST_PA
(fbf
), %esi; \
74 addl FB_SEC_OFFSET
(fbs
), %esi; \
75 movl FB_SEC_PADDR
(fbs
), %edi; \
76 movl FB_SEC_SIZE
(fbs
), %ecx; \
80 movl FB_SEC_BSS_SIZE
(fbs
), %ecx; \
83 add $FB_SECTIONS_INCR
, fbs; \
91 /* Disable interrupts */
95 /* Switch to a low memory stack */
97 addq $FASTBOOT_STACK_OFFSET
, %rsp
100 * Copy from old stack to new stack
101 * If the content before fi_valid gets bigger than 0x200 bytes,
102 * the reserved stack size above will need to be changed.
104 movq
%rdi
, %rsi
/* source from old stack */
105 movq
%rsp
, %rdi
/* destination on the new stack */
106 movq $FI_VALID
, %rcx
/* size to copy */
110 #elif defined(__i386)
111 movl
0x4(%esp
), %esi
/* address of fastboot info struct */
113 /* Switch to a low memory stack */
115 addl $FASTBOOT_STACK_OFFSET
, %esp
117 /* Copy struct to stack */
118 movl
%esp
, %edi
/* destination on the new stack */
119 movl $FI_VALID
, %ecx
/* size to copy */
130 movl $MSR_AMD_FSBASE
, %ecx
133 movl $MSR_AMD_GSBASE
, %ecx
136 movl $MSR_AMD_KGSBASE
, %ecx
141 * zero out all the registers to make sure they're 16 bit clean
172 * Invalidate all TLB entries.
173 * Load temporary pagetables to copy kernel and boot-archive
176 andq $_BITNOT
(CR4_PGE
), %rax
178 movq FI_PAGETABLE_PA
(%rsp
), %rax
181 leaq FI_FILES
(%rsp
), %rbx
/* offset to the files */
183 /* copy unix to final destination */
184 movq FI_LAST_TABLE_PA
(%rsp
), %rsi
/* page table PA */
185 leaq _MUL
(FASTBOOT_UNIX
, FI_FILES_INCR
)(%rbx
), %rdi
188 /* copy boot archive to final destination */
189 movq FI_LAST_TABLE_PA
(%rsp
), %rsi
/* page table PA */
190 leaq _MUL
(FASTBOOT_BOOTARCHIVE
, FI_FILES_INCR
)(%rbx
), %rdi
193 /* Copy sections if there are any */
194 leaq _MUL
(FASTBOOT_UNIX
, FI_FILES_INCR
)(%rbx
), %rdi
195 movl FB_SECTCNT
(%rdi
), %esi
201 * Shut down 64 bit mode. First get into compatiblity mode.
213 movl $B32DATA_SEL
, %eax
221 * Disable long mode by:
222 * - shutting down paging (bit 31 of cr0). This will flush the
224 * - turning off PCID in cr4
225 * - disabling LME (long mode enable) in EFER (extended feature reg)
228 DISABLE_PAGING
/* clobbers %eax */
231 ljmp $B32CODE_SEL
, $
1f
236 * Clear PGE, PAE and PSE flags as dboot expects them to be
240 andl $_BITNOT
(CR4_PGE | CR4_PAE | CR4_PSE
), %eax
244 movl $MSR_AMD_EFER
, %ecx
/* Extended Feature Enable */
246 btcl $
8, %eax
/* bit 8 Long Mode Enable bit */
249 #elif defined(__i386)
251 * If fi_has_pae is set, re-enable paging with PAE.
253 leal FI_FILES
(%esp
), %ebx
/* offset to the files */
254 movl FI_HAS_PAE
(%esp
), %edi
/* need to enable paging or not */
256 je paging_on
/* no need to enable paging */
258 movl FI_LAST_TABLE_PA
(%esp
), %esi
/* page table PA */
268 * Load top pagetable base address into cr3
270 movl FI_PAGETABLE_PA
(%esp
), %eax
274 orl $_CONST
(CR0_PG | CR0_WP | CR0_AM
), %eax
275 andl $_BITNOT
(CR0_NW | CR0_CD
), %eax
280 /* copy unix to final destination */
281 leal _MUL
(FASTBOOT_UNIX
, FI_FILES_INCR
)(%ebx
), %edx
284 /* copy boot archive to final destination */
285 leal _MUL
(FASTBOOT_BOOTARCHIVE
, FI_FILES_INCR
)(%ebx
), %edx
288 /* Disable paging one more time */
291 /* Copy sections if there are any */
292 leal _MUL
(FASTBOOT_UNIX
, FI_FILES_INCR
)(%ebx
), %edx
293 movl FB_SECTCNT
(%edx
), %eax
299 /* Whatever flags we turn on we need to turn off */
301 andl $_BITNOT
(CR4_PAE
), %eax
307 movl $DBOOT_ENTRY_ADDRESS
, %edi
308 movl FI_NEW_MBI_PA
(%esp
), %ebx
309 movl $MB_BOOTLOADER_MAGIC
, %eax
315 ENTRY_NP
(copy_sections
)
318 * %rdi points to the fboot_file_t
319 * %rsi contains number of sections
324 COPY_SECT
(%rdx
, %r8, %r9)
326 SET_SIZE
(copy_sections
)
331 * %rdi points to the fboot_file_t
332 * %rsi has FI_LAST_TABLE_PA(%rsp)
337 movq FB_PTE_LIST_PA
(%rdx
), %rax
/* PA list of the source */
338 movq FB_DEST_PA
(%rdx
), %rdi
/* PA of the destination */
341 movq
(%rax
), %rcx
/* Are we done? */
342 cmpl $FASTBOOT_TERMINATE
, %ecx
346 movq
%cr3
, %rsi
/* Reload cr3 */
348 movq FB_VA
(%rdx
), %rsi
/* Load from VA */
350 shrq $
3, %rcx
/* 8-byte at a time */
353 addq $
8, %rax
/* Go to next PTE */
359 #elif defined(__i386)
361 ENTRY_NP
(copy_sections
)
364 * %edx points to the fboot_file_t
365 * %eax contains the number of sections
374 COPY_SECT
(%edx
, %ebx
, %ebp
)
381 SET_SIZE
(copy_sections
)
386 * %edx points to the fboot_file_t
387 * %edi has FB_HAS_PAE(%esp)
388 * %esi has FI_LAST_TABLE_PA(%esp)
397 movl
%esi
, %ebp
/* Save page table PA in %ebp */
399 movl FB_PTE_LIST_PA
(%edx
), %eax
/* PA list of the source */
400 movl FB_DEST_PA
(%edx
), %ebx
/* PA of the destination */
403 movl
(%eax
), %esi
/* Are we done? */
404 cmpl $FASTBOOT_TERMINATE
, %esi
407 cmpl $
1, (%esp
) /* Is paging on? */
408 jne no_paging
/* Nope */
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 */
416 movl FB_VA
(%edx
), %esi
/* Load from VA */
419 andl $_BITNOT
(MMU_PAGEOFFSET
), %esi
/* clear lower 12-bit */
423 shrl $
2, %ecx
/* 4-byte at a time */
426 addl $
8, %eax
/* We built the PTEs as 8-byte entries */
447 * We need to trampoline thru a gdt we have in low memory.
449 #include "../boot/boot_gdt.s"