xref: /titanic_50/usr/src/uts/i86pc/ml/fb_swtch_src.s (revision 34f9b3eef6fdadbda0a846aa4d68691ac40eace5)
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
30int 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;			\
741:	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
2001:
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
2131:
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
2321:
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
278paging_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
2971:
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
305dboot_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
3402:
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
3551:
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
402loop:
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
418no_paging:
419	andl	$_BITNOT(MMU_PAGEOFFSET), %esi	/* clear lower 12-bit */
420do_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
429done:
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
442idt_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