Merge commit '74ecdb5171c9f3673b9393b1a3dc6f3a65e93895'
[unleashed.git] / arch / x86 / kernel / platform / i86pc / boot / fb_swtch_src.s
blobaa5e04cb0b91cbbc3a722f05dbf8b62f679a02f8
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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>
36 #include "assym.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) \
46 movb val, %al; \
47 outb $0x80;
50 #define DISABLE_PAGING \
51 movl %cr4, %eax ;\
52 btrl $17, %eax /* clear PCIDE bit */ ;\
53 movl %eax, %cr4 ;\
54 movl %cr0, %eax ;\
55 btrl $31, %eax /* clear PG bit */ ;\
56 movl %eax, %cr0
59 * This macro contains common code for 64/32-bit versions of copy_sections().
60 * On entry:
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; \
72 xorl %eax, %eax; \
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; \
77 rep \
78 movsb; \
79 /* Zero BSS */ \
80 movl FB_SEC_BSS_SIZE(fbs), %ecx; \
81 rep \
82 stosb; \
83 add $FB_SECTIONS_INCR, fbs; \
84 dec snum; \
85 jnz 1b
88 .globl _start
89 _start:
91 /* Disable interrupts */
92 cli
94 #if defined(__amd64)
95 /* Switch to a low memory stack */
96 movq $_start, %rsp
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 */
108 smovb
110 #elif defined(__i386)
111 movl 0x4(%esp), %esi /* address of fastboot info struct */
113 /* Switch to a low memory stack */
114 movl $_start, %esp
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 */
121 smovb
123 #endif
125 #if defined(__amd64)
127 xorl %eax, %eax
128 xorl %edx, %edx
130 movl $MSR_AMD_FSBASE, %ecx
131 wrmsr
133 movl $MSR_AMD_GSBASE, %ecx
134 wrmsr
136 movl $MSR_AMD_KGSBASE, %ecx
137 wrmsr
139 #endif
141 * zero out all the registers to make sure they're 16 bit clean
143 #if defined(__amd64)
144 xorq %r8, %r8
145 xorq %r9, %r9
146 xorq %r10, %r10
147 xorq %r11, %r11
148 xorq %r12, %r12
149 xorq %r13, %r13
150 xorq %r14, %r14
151 xorq %r15, %r15
152 #endif
153 xorl %eax, %eax
154 xorl %ebx, %ebx
155 xorl %ecx, %ecx
156 xorl %edx, %edx
157 xorl %ebp, %ebp
159 #if defined(__amd64)
161 * Load our own GDT
163 lgdt gdt_info
164 #endif
166 * Load our own IDT
168 lidt idt_info
170 #if defined(__amd64)
172 * Invalidate all TLB entries.
173 * Load temporary pagetables to copy kernel and boot-archive
175 movq %cr4, %rax
176 andq $_BITNOT(CR4_PGE), %rax
177 movq %rax, %cr4
178 movq FI_PAGETABLE_PA(%rsp), %rax
179 movq %rax, %cr3
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
186 call map_copy
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
191 call map_copy
193 /* Copy sections if there are any */
194 leaq _MUL(FASTBOOT_UNIX, FI_FILES_INCR)(%rbx), %rdi
195 movl FB_SECTCNT(%rdi), %esi
196 cmpl $0, %esi
197 je 1f
198 call copy_sections
201 * Shut down 64 bit mode. First get into compatiblity mode.
203 movq %rsp, %rax
204 pushq $B32DATA_SEL
205 pushq %rax
206 pushf
207 pushq $B32CODE_SEL
208 pushq $1f
209 iretq
211 .code32
213 movl $B32DATA_SEL, %eax
214 movw %ax, %ss
215 movw %ax, %ds
216 movw %ax, %es
217 movw %ax, %fs
218 movw %ax, %gs
221 * Disable long mode by:
222 * - shutting down paging (bit 31 of cr0). This will flush the
223 * TLBs.
224 * - turning off PCID in cr4
225 * - disabling LME (long mode enable) in EFER (extended feature reg)
227 #endif
228 DISABLE_PAGING /* clobbers %eax */
230 #if defined(__amd64)
231 ljmp $B32CODE_SEL, $1f
233 #endif
236 * Clear PGE, PAE and PSE flags as dboot expects them to be
237 * cleared.
239 movl %cr4, %eax
240 andl $_BITNOT(CR4_PGE | CR4_PAE | CR4_PSE), %eax
241 movl %eax, %cr4
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
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 */
255 cmpl $0, %edi
256 je paging_on /* no need to enable paging */
258 movl FI_LAST_TABLE_PA(%esp), %esi /* page table PA */
261 * Turn on PAE
263 movl %cr4, %eax
264 orl $CR4_PAE, %eax
265 movl %eax, %cr4
268 * Load top pagetable base address into cr3
270 movl FI_PAGETABLE_PA(%esp), %eax
271 movl %eax, %cr3
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:
280 /* copy unix to final destination */
281 leal _MUL(FASTBOOT_UNIX, FI_FILES_INCR)(%ebx), %edx
282 call map_copy
284 /* copy boot archive to final destination */
285 leal _MUL(FASTBOOT_BOOTARCHIVE, FI_FILES_INCR)(%ebx), %edx
286 call map_copy
288 /* Disable paging one more time */
289 DISABLE_PAGING
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
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 */
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
312 #if defined(__amd64)
314 .code64
315 ENTRY_NP(copy_sections)
317 * On entry
318 * %rdi points to the fboot_file_t
319 * %rsi contains number of sections
321 movq %rdi, %rdx
322 movq %rsi, %r9
324 COPY_SECT(%rdx, %r8, %r9)
326 SET_SIZE(copy_sections)
328 ENTRY_NP(map_copy)
330 * On entry
331 * %rdi points to the fboot_file_t
332 * %rsi has FI_LAST_TABLE_PA(%rsp)
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 */
341 movq (%rax), %rcx /* Are we done? */
342 cmpl $FASTBOOT_TERMINATE, %ecx
343 je 1f
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 */
352 smovq
353 addq $8, %rax /* Go to next PTE */
354 jmp 2b
357 SET_SIZE(map_copy)
359 #elif defined(__i386)
361 ENTRY_NP(copy_sections)
363 * On entry
364 * %edx points to the fboot_file_t
365 * %eax contains the number of sections
367 pushl %ebp
368 pushl %ebx
369 pushl %esi
370 pushl %edi
372 movl %eax, %ebp
374 COPY_SECT(%edx, %ebx, %ebp)
376 popl %edi
377 popl %esi
378 popl %ebx
379 popl %ebp
381 SET_SIZE(copy_sections)
383 ENTRY_NP(map_copy)
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)
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 */
399 movl FB_PTE_LIST_PA(%edx), %eax /* PA list of the source */
400 movl FB_DEST_PA(%edx), %ebx /* PA of the destination */
402 loop:
403 movl (%eax), %esi /* Are we done? */
404 cmpl $FASTBOOT_TERMINATE, %esi
405 je done
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 */
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 */
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
438 SET_SIZE(map_copy)
439 #endif /* __i386 */
442 idt_info:
443 .value 0x3ff
444 .quad 0
447 * We need to trampoline thru a gdt we have in low memory.
449 #include "../boot/boot_gdt.s"