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]
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 #include <sys/segments.h>
31 #include <sys/controlregs.h>
34 * Do a call into BIOS. This goes down to 16 bit real mode and back again.
38 * instruction prefix to change operand size in instruction
40 #define DATASZ .byte 0x66;
43 #define MOVCR(x, y) movq x,%rax; movq %rax, y
44 #define LOAD_XAX(sym) leaq sym, %rax
46 #define MOVCR(x, y) movl x,%eax; movl %eax, y
47 #define LOAD_XAX(sym) leal sym, %eax
56 * Save caller registers
64 /* get registers argument into esi */
67 /* put interrupt number in %bl */
70 /* Switch to a low memory stack */
73 /* allocate space for args on stack */
77 #elif defined(__amd64)
80 * Save caller registers
91 /* Switch to a low memory stack */
94 /* put interrupt number in %bl */
97 /* allocate space for args on stack */
103 /* copy args from high memory to stack in low memory */
110 * Save system registers
121 MOVCR
( %cr4
, save_cr4
)
122 MOVCR
( %cr3
, save_cr3
)
123 MOVCR
( %cr0, save_cr0
)
127 * save/clear the extension parts of the fs/gs base registers and cr8
129 movl $MSR_AMD_FSBASE
, %ecx
131 movl
%eax
, save_fsbase
132 movl
%edx
, save_fsbase
+ 4
137 movl $MSR_AMD_GSBASE
, %ecx
139 movl
%eax
, save_gsbase
140 movl
%edx
, save_gsbase
+ 4
145 movl $MSR_AMD_KGSBASE
, %ecx
147 movl
%eax
, save_kgsbase
148 movl
%edx
, save_kgsbase
+ 4
158 * set offsets in 16 bit ljmp instructions below
161 movw
%ax
, enter_real_ljmp
163 LOAD_XAX
(enter_protected
)
164 movw
%ax
, enter_protected_ljmp
167 movw
%ax
, gdt_info_load
170 * insert BIOS interrupt number into later instruction
172 movb
%bl, int_instr+
1
177 * zero out all the registers to make sure they're 16 bit clean
198 * Load our own GDT/IDT
205 * Shut down 64 bit mode. First get into compatiblity mode.
218 * disable long mode by:
219 * - shutting down paging (bit 31 of cr0)
221 * - disabling LME (long made enable) in EFER (extended feature reg)
224 btcl $
31, %eax
/* disable paging */
226 ljmp $B32CODE_SEL
, $
1f
230 movl
%eax
, %cr3
/* flushes TLB */
232 movl $MSR_AMD_EFER
, %ecx
/* Extended Feature Enable */
234 btcl $
8, %eax
/* bit 8 Long Mode Enable bit */
239 * ok.. now enter 16 bit mode, so we can shut down protected mode
241 * We'll have to act like we're still in a 32 bit section.
242 * So the code from this point has DATASZ in front of it to get 32 bit
243 * operands. If DATASZ is missing the operands will be 16 bit.
245 * Now shut down paging and protected (ie. segmentation) modes.
247 ljmp $B16CODE_SEL
, $enter_16_bit
251 * Make sure hidden parts of segment registers are 16 bit clean
253 DATASZ movl $B16DATA_SEL
, %eax
261 DATASZ movl $
0x0, %eax
/* put us in real mode */
262 DATASZ movl
%eax
, %cr0
263 .byte 0xea /* ljmp */
265 .value 0 /* addr (16 bit) */
266 .value 0x0 /* value for %cs */
270 * zero out the remaining segment registers
272 DATASZ xorl
%eax
, %eax
280 * load the arguments to the BIOS call from the stack
282 popl
%eax
/* really executes a 16 bit pop */
293 * do the actual BIOS call
297 int $
0x10 /* this int number is overwritten */
298 cli /* ensure interrupts remain disabled */
301 * save results of the BIOS call
306 pushl
%ebp
/* still executes as 16 bit */
315 * Restore protected mode and 32 bit execution
317 push $
0 /* make sure %ds is zero before lgdt */
319 .byte 0x0f, 0x01, 0x16 /* lgdt */
321 .value 0 /* temp GDT in currently addressible mem */
323 DATASZ movl $
0x1, %eax
324 DATASZ movl
%eax
, %cr0
326 .byte 0xea /* ljmp */
327 enter_protected_ljmp
:
328 .value 0 /* addr (still in 16 bit) */
329 .value B32CODE_SEL /* %cs value */
333 * We are now back in a 32 bit code section, fix data/stack segments
336 movw $B32DATA_SEL
, %ax
341 * Re-enable paging. Note we only use 32 bit mov's to restore these
342 * control registers. That's OK as the upper 32 bits are always zero.
351 * re-enable long mode
353 movl $MSR_AMD_EFER
, %ecx
367 * transition back to 64 bit mode
376 * restore caller frame pointer and segment registers
382 * Before loading the task register we need to reset the busy bit
383 * in its corresponding GDT selector. The busy bit is the 2nd bit in
384 * the 5th byte of the selector.
388 addl save_gdt+
2, %eax
390 #elif defined(__amd64)
392 addq save_gdt+
2, %rax
406 #elif defined(__amd64)
415 * restore the hidden kernel segment base register values
417 movl save_fsbase
, %eax
418 movl save_fsbase
+ 4, %edx
419 movl $MSR_AMD_FSBASE
, %ecx
422 movl save_gsbase
, %eax
423 movl save_gsbase
+ 4, %edx
424 movl $MSR_AMD_GSBASE
, %ecx
427 movl save_kgsbase
, %eax
428 movl save_kgsbase
+ 4, %edx
429 movl $MSR_AMD_KGSBASE
, %ecx
440 * copy results to caller's location, then restore remaining registers
459 #elif defined(__amd64)
480 * Caller's registers to restore
557 * We need to trampoline thru a gdt we have in low memory.
559 #include "../boot/boot_gdt.s"