Home | History | Annotate | Download | only in ml
      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 */
    451