fb_swtch_src.s revision 877400d375b54199aef7c18828cb32f991339ff7
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#if defined(__lint)
int fb_swtch_silence_lint = 0;
#else
#include <sys/asm_linkage.h>
#include <sys/segments.h>
#include <sys/controlregs.h>
#include <sys/machparam.h>
#include <sys/multiboot.h>
#include <sys/fastboot.h>
#include "assym.h"
/*
* This code is to switch from 64-bit or 32-bit to protected mode.
*/
/*
* For debugging with LEDs
*/
#define FB_OUTB_ASM(val) \
movb val, %al; \
outb $0x80;
#define DISABLE_PAGING \
movl %cr0, %eax ;\
btrl $31, %eax /* clear PG bit */ ;\
movl %eax, %cr0
/*
* This macro contains common code for 64/32-bit versions of copy_sections().
* On entry:
* fbf points to the fboot_file_t
* snum contains the number of sections
* Registers that would be clobbered:
* fbs, snum, %eax, %ecx, %edi, %esi.
* NOTE: fb_dest_pa is supposed to be in the first 1GB,
* therefore it is safe to use 32-bit register to hold it's value
* even for 64-bit code.
*/
#define COPY_SECT(fbf, fbs, snum) \
lea FB_SECTIONS(fbf), fbs; \
xorl %eax, %eax; \
1: movl FB_DEST_PA(fbf), %esi; \
addl FB_SEC_OFFSET(fbs), %esi; \
movl FB_SEC_PADDR(fbs), %edi; \
movl FB_SEC_SIZE(fbs), %ecx; \
rep \
movsb; \
/* Zero BSS */ \
movl FB_SEC_BSS_SIZE(fbs), %ecx; \
rep \
stosb; \
add $FB_SECTIONS_INCR, fbs; \
dec snum; \
jnz 1b
.globl _start
_start:
/* Disable interrupts */
cli
#if defined(__amd64)
/* Switch to a low memory stack */
movq $_start, %rsp
addq $FASTBOOT_STACK_OFFSET, %rsp
/*
* Copy from old stack to new stack
* If the content before fi_valid gets bigger than 0x200 bytes,
* the reserved stack size above will need to be changed.
*/
movq %rdi, %rsi /* source from old stack */
movq %rsp, %rdi /* destination on the new stack */
movq $FI_VALID, %rcx /* size to copy */
rep
smovb
#elif defined(__i386)
movl 0x4(%esp), %esi /* address of fastboot info struct */
/* Switch to a low memory stack */
movl $_start, %esp
addl $FASTBOOT_STACK_OFFSET, %esp
/* Copy struct to stack */
movl %esp, %edi /* destination on the new stack */
movl $FI_VALID, %ecx /* size to copy */
rep
smovb
#endif
#if defined(__amd64)
xorl %eax, %eax
xorl %edx, %edx
movl $MSR_AMD_FSBASE, %ecx
wrmsr
movl $MSR_AMD_GSBASE, %ecx
wrmsr
movl $MSR_AMD_KGSBASE, %ecx
wrmsr
#endif
/*
* zero out all the registers to make sure they're 16 bit clean
*/
#if defined(__amd64)
xorq %r8, %r8
xorq %r9, %r9
xorq %r10, %r10
xorq %r11, %r11
xorq %r12, %r12
xorq %r13, %r13
xorq %r14, %r14
xorq %r15, %r15
#endif
xorl %eax, %eax
xorl %ebx, %ebx
xorl %ecx, %ecx
xorl %edx, %edx
xorl %ebp, %ebp
#if defined(__amd64)
/*
* Load our own GDT
*/
lgdt gdt_info
#endif
/*
* Load our own IDT
*/
lidt idt_info
#if defined(__amd64)
/*
* Invalidate all TLB entries.
* Load temporary pagetables to copy kernel and boot-archive
*/
movq %cr4, %rax
andq $_BITNOT(CR4_PGE), %rax
movq %rax, %cr4
movq FI_PAGETABLE_PA(%rsp), %rax
movq %rax, %cr3
leaq FI_FILES(%rsp), %rbx /* offset to the files */
/* copy unix to final destination */
movq FI_LAST_TABLE_PA(%rsp), %rsi /* page table PA */
leaq _MUL(FASTBOOT_UNIX, FI_FILES_INCR)(%rbx), %rdi
call map_copy
/* copy boot archive to final destination */
movq FI_LAST_TABLE_PA(%rsp), %rsi /* page table PA */
leaq _MUL(FASTBOOT_BOOTARCHIVE, FI_FILES_INCR)(%rbx), %rdi
call map_copy
/* Copy sections if there are any */
leaq _MUL(FASTBOOT_UNIX, FI_FILES_INCR)(%rbx), %rdi
movl FB_SECTCNT(%rdi), %esi
cmpl $0, %esi
je 1f
call copy_sections
1:
/*
* Shut down 64 bit mode. First get into compatiblity mode.
*/
movq %rsp, %rax
pushq $B32DATA_SEL
pushq %rax
pushf
pushq $B32CODE_SEL
pushq $1f
iretq
.code32
1:
movl $B32DATA_SEL, %eax
movw %ax, %ss
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
/*
* Disable long mode by:
* - shutting down paging (bit 31 of cr0). This will flush the
* TLBs.
* - disabling LME (long mode enable) in EFER (extended feature reg)
*/
#endif
DISABLE_PAGING /* clobbers %eax */
#if defined(__amd64)
ljmp $B32CODE_SEL, $1f
1:
#endif
/*
* Clear PGE, PAE and PSE flags as dboot expects them to be
* cleared.
*/
movl %cr4, %eax
andl $_BITNOT(CR4_PGE | CR4_PAE | CR4_PSE), %eax
movl %eax, %cr4
#if defined(__amd64)
movl $MSR_AMD_EFER, %ecx /* Extended Feature Enable */
rdmsr
btcl $8, %eax /* bit 8 Long Mode Enable bit */
wrmsr
#elif defined(__i386)
/*
* If fi_has_pae is set, re-enable paging with PAE.
*/
leal FI_FILES(%esp), %ebx /* offset to the files */
movl FI_HAS_PAE(%esp), %edi /* need to enable paging or not */
cmpl $0, %edi
je paging_on /* no need to enable paging */
movl FI_LAST_TABLE_PA(%esp), %esi /* page table PA */
/*
* Turn on PAE
*/
movl %cr4, %eax
orl $CR4_PAE, %eax
movl %eax, %cr4
/*
* Load top pagetable base address into cr3
*/
movl FI_PAGETABLE_PA(%esp), %eax
movl %eax, %cr3
movl %cr0, %eax
orl $_CONST(CR0_PG | CR0_WP | CR0_AM), %eax
andl $_BITNOT(CR0_NW | CR0_CD), %eax
movl %eax, %cr0
jmp paging_on
paging_on:
/* copy unix to final destination */
leal _MUL(FASTBOOT_UNIX, FI_FILES_INCR)(%ebx), %edx
call map_copy
/* copy boot archive to final destination */
leal _MUL(FASTBOOT_BOOTARCHIVE, FI_FILES_INCR)(%ebx), %edx
call map_copy
/* Disable paging one more time */
DISABLE_PAGING
/* Copy sections if there are any */
leal _MUL(FASTBOOT_UNIX, FI_FILES_INCR)(%ebx), %edx
movl FB_SECTCNT(%edx), %eax
cmpl $0, %eax
je 1f
call copy_sections
1:
/* Whatever flags we turn on we need to turn off */
movl %cr4, %eax
andl $_BITNOT(CR4_PAE), %eax
movl %eax, %cr4
#endif /* __i386 */
dboot_jump:
/* Jump to dboot */
movl $DBOOT_ENTRY_ADDRESS, %edi
movl FI_NEW_MBI_PA(%esp), %ebx
movl $MB_BOOTLOADER_MAGIC, %eax
jmp *%edi
#if defined(__amd64)
.code64
ENTRY_NP(copy_sections)
/*
* On entry
* %rdi points to the fboot_file_t
* %rsi contains number of sections
*/
movq %rdi, %rdx
movq %rsi, %r9
COPY_SECT(%rdx, %r8, %r9)
ret
SET_SIZE(copy_sections)
ENTRY_NP(map_copy)
/*
* On entry
* %rdi points to the fboot_file_t
* %rsi has FI_LAST_TABLE_PA(%rsp)
*/
movq %rdi, %rdx
movq %rsi, %r8
movq FB_PTE_LIST_PA(%rdx), %rax /* PA list of the source */
movq FB_DEST_PA(%rdx), %rdi /* PA of the destination */
2:
movq (%rax), %rcx /* Are we done? */
cmpl $FASTBOOT_TERMINATE, %ecx
je 1f
movq %rcx, (%r8)
movq %cr3, %rsi /* Reload cr3 */
movq %rsi, %cr3
movq FB_VA(%rdx), %rsi /* Load from VA */
movq $PAGESIZE, %rcx
shrq $3, %rcx /* 8-byte at a time */
rep
smovq
addq $8, %rax /* Go to next PTE */
jmp 2b
1:
ret
SET_SIZE(map_copy)
#elif defined(__i386)
ENTRY_NP(copy_sections)
/*
* On entry
* %edx points to the fboot_file_t
* %eax contains the number of sections
*/
pushl %ebp
pushl %ebx
pushl %esi
pushl %edi
movl %eax, %ebp
COPY_SECT(%edx, %ebx, %ebp)
popl %edi
popl %esi
popl %ebx
popl %ebp
ret
SET_SIZE(copy_sections)
ENTRY_NP(map_copy)
/*
* On entry
* %edx points to the fboot_file_t
* %edi has FB_HAS_PAE(%esp)
* %esi has FI_LAST_TABLE_PA(%esp)
*/
pushl %eax
pushl %ebx
pushl %ecx
pushl %edx
pushl %ebp
pushl %esi
pushl %edi
movl %esi, %ebp /* Save page table PA in %ebp */
movl FB_PTE_LIST_PA(%edx), %eax /* PA list of the source */
movl FB_DEST_PA(%edx), %ebx /* PA of the destination */
loop:
movl (%eax), %esi /* Are we done? */
cmpl $FASTBOOT_TERMINATE, %esi
je done
cmpl $1, (%esp) /* Is paging on? */
jne no_paging /* Nope */
movl %ebp, %edi /* Page table PA */
movl %esi, (%edi) /* Program low 32-bit */
movl 4(%eax), %esi /* high bits of the table */
movl %esi, 4(%edi) /* Program high 32-bit */
movl %cr3, %esi /* Reload cr3 */
movl %esi, %cr3
movl FB_VA(%edx), %esi /* Load from VA */
jmp do_copy
no_paging:
andl $_BITNOT(MMU_PAGEOFFSET), %esi /* clear lower 12-bit */
do_copy:
movl %ebx, %edi
movl $PAGESIZE, %ecx
shrl $2, %ecx /* 4-byte at a time */
rep
smovl
addl $8, %eax /* We built the PTEs as 8-byte entries */
addl $PAGESIZE, %ebx
jmp loop
done:
popl %edi
popl %esi
popl %ebp
popl %edx
popl %ecx
popl %ebx
popl %eax
ret
SET_SIZE(map_copy)
#endif /* __i386 */
idt_info:
.value 0x3ff
.quad 0
/*
* We need to trampoline thru a gdt we have in low memory.
*/
#include "../boot/boot_gdt.s"
#endif /* __lint */