xref: /illumos-gate/usr/src/uts/i86pc/ml/fb_swtch_src.S (revision 55fea89d)
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;			\
721:	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
1741:
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
1871:
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
2051:
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
220dboot_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
2532:
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
2681:
269	ret
270	SET_SIZE(map_copy)
271
272idt_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"
280