blob: c4c4c4378e94a140094ab2bf233dd24d218d0148 [file] [log] [blame]
wdenk591dda52002-11-18 00:14:45 +00001/*
2 * (C) Copyright 2002
Albert ARIBAUD60fbc8d2011-08-04 18:45:45 +02003 * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
wdenk57b2d802003-06-27 21:31:46 +00004 *
wdenk591dda52002-11-18 00:14:45 +00005 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
wdenk591dda52002-11-18 00:14:45 +000024/* 32bit -> 16bit -> 32bit mode switch code */
25
26/*
27 * Stack frame at 0xe00
Wolfgang Denka1be4762008-05-20 16:00:29 +020028 * e00 ebx;
wdenk591dda52002-11-18 00:14:45 +000029 * e04 ecx;
30 * e08 edx;
31 * e0c esi;
32 * e10 edi;
wdenk57b2d802003-06-27 21:31:46 +000033 * e14 ebp;
wdenk591dda52002-11-18 00:14:45 +000034 * e18 eax;
wdenk57b2d802003-06-27 21:31:46 +000035 * e1c ds;
wdenk591dda52002-11-18 00:14:45 +000036 * e20 es;
wdenk57b2d802003-06-27 21:31:46 +000037 * e24 fs;
wdenk591dda52002-11-18 00:14:45 +000038 * e28 gs;
39 * e2c orig_eax;
40 * e30 eip;
41 * e34 cs;
42 * e38 eflags;
43 * e3c esp;
44 * e40 ss;
45 */
46
Graeme Russ6dda1312011-12-19 20:00:40 +110047#define a32 .byte 0x67; /* address size prefix 32 */
48#define o32 .byte 0x66; /* operand size prefix 32 */
wdenk591dda52002-11-18 00:14:45 +000049
50.section .realmode, "ax"
51.code16
Graeme Russ6dda1312011-12-19 20:00:40 +110052
53 /* 16bit protected mode code here */
wdenk591dda52002-11-18 00:14:45 +000054.globl realmode_enter
55realmode_enter:
56o32 pusha
57o32 pushf
58 cli
Wolfgang Denka1be4762008-05-20 16:00:29 +020059 sidt saved_idt
60 sgdt saved_gdt
61 movl %esp, %eax
62 movl %eax, saved_protected_mode_esp
wdenk57b2d802003-06-27 21:31:46 +000063
wdenk591dda52002-11-18 00:14:45 +000064 movl $0x10, %eax
Wolfgang Denka1be4762008-05-20 16:00:29 +020065 movl %eax, %esp
wdenk591dda52002-11-18 00:14:45 +000066 movw $0x28, %ax
67 movw %ax, %ds
68 movw %ax, %es
69 movw %ax, %fs
70 movw %ax, %gs
71
72 lidt realmode_idt_ptr
Graeme Russ6dda1312011-12-19 20:00:40 +110073 /* Go back into real mode by clearing PE to 0 */
74 movl %cr0, %eax
75 andl $0x7ffffffe, %eax
wdenk591dda52002-11-18 00:14:45 +000076 movl %eax, %cr0
wdenk57b2d802003-06-27 21:31:46 +000077
Graeme Russ6dda1312011-12-19 20:00:40 +110078 /* switch to real mode */
79 ljmp $0x0,$do_realmode
80
81do_realmode:
82 /* realmode code from here */
wdenk591dda52002-11-18 00:14:45 +000083 movw %cs,%ax
84 movw %ax,%ds
85 movw %ax,%es
86 movw %ax,%fs
87 movw %ax,%gs
wdenk57b2d802003-06-27 21:31:46 +000088
Graeme Russ6dda1312011-12-19 20:00:40 +110089 /* create a temporary stack */
wdenk57b2d802003-06-27 21:31:46 +000090 movw $0xc0, %ax
91 movw %ax, %ss
92 movw $0x200, %ax
93 movw %ax, %sp
94
wdenk591dda52002-11-18 00:14:45 +000095 popl %ebx
96 popl %ecx
97 popl %edx
98 popl %esi
99 popl %edi
100 popl %ebp
101 popl %eax
102 movl %eax, temp_eax
103 popl %eax
104 movw %ax, %ds
105 popl %eax
106 movw %ax, %es
107 popl %eax
108 movw %ax, %fs
109 popl %eax
110 movw %ax, %gs
111 popl %eax /* orig_eax */
112 popl %eax
113cs movw %ax, temp_ip
114 popl %eax
115cs movw %ax, temp_cs
116o32 popf
117 popl %eax
118 popw %ss
119 movl %eax, %esp
120cs movl temp_eax, %eax
Graeme Russ6dda1312011-12-19 20:00:40 +1100121
122 /* self-modifying code, better flush the cache */
123 wbinvd
wdenk57b2d802003-06-27 21:31:46 +0000124
wdenk591dda52002-11-18 00:14:45 +0000125 .byte 0x9a /* lcall */
126temp_ip:
Wolfgang Denka1be4762008-05-20 16:00:29 +0200127 .word 0 /* new ip */
wdenk57b2d802003-06-27 21:31:46 +0000128temp_cs:
Wolfgang Denka1be4762008-05-20 16:00:29 +0200129 .word 0 /* new cs */
Graeme Russ6dda1312011-12-19 20:00:40 +1100130
wdenk591dda52002-11-18 00:14:45 +0000131realmode_ret:
Graeme Russ6dda1312011-12-19 20:00:40 +1100132 /* save eax, esp and ss */
wdenk591dda52002-11-18 00:14:45 +0000133cs movl %eax, saved_eax
134 movl %esp, %eax
135cs movl %eax, saved_esp
Wolfgang Denka1be4762008-05-20 16:00:29 +0200136 movw %ss, %ax
wdenk591dda52002-11-18 00:14:45 +0000137cs movw %ax, saved_ss
wdenk57b2d802003-06-27 21:31:46 +0000138
Graeme Russ6dda1312011-12-19 20:00:40 +1100139 /*
140 * restore the stack, note that we set sp to 0x244;
wdenk591dda52002-11-18 00:14:45 +0000141 * pt_regs is 0x44 bytes long and we push the structure
Graeme Russ6dda1312011-12-19 20:00:40 +1100142 * backwards on to the stack, bottom first
143 */
wdenk57b2d802003-06-27 21:31:46 +0000144 movw $0xc0, %ax
145 movw %ax, %ss
146 movw $0x244, %ax
147 movw %ax, %sp
148
wdenk591dda52002-11-18 00:14:45 +0000149 xorl %eax,%eax
150cs movw saved_ss, %ax
151 pushl %eax
152cs movl saved_esp, %eax
153 pushl %eax
154o32 pushf
155 xorl %eax,%eax
156cs movw temp_cs, %ax
157 pushl %eax
158cs movw temp_ip, %ax
159 pushl %eax
160 pushl $0
161 movw %gs, %ax
162 pushl %eax
163 movw %fs, %ax
164 pushl %eax
165 movw %es, %ax
166 pushl %eax
167 movw %ds, %ax
168 pushl %eax
169 movl saved_eax, %eax
170 pushl %eax
171 pushl %ebp
172 pushl %edi
173 pushl %esi
174 pushl %edx
175 pushl %ecx
176 pushl %ebx
177
178o32 cs lidt saved_idt
Graeme Russ6dda1312011-12-19 20:00:40 +1100179o32 cs lgdt saved_gdt
wdenk591dda52002-11-18 00:14:45 +0000180
Graeme Russ6dda1312011-12-19 20:00:40 +1100181 /* Go back into protected mode reset PE to 1 */
182 movl %cr0, %eax
183 orl $1,%eax
Wolfgang Denka1be4762008-05-20 16:00:29 +0200184 movl %eax, %cr0
Graeme Russ6dda1312011-12-19 20:00:40 +1100185
186 /* flush prefetch queue */
187 jmp next_line
wdenk57b2d802003-06-27 21:31:46 +0000188next_line:
189 movw $return_ptr, %ax
Wolfgang Denka1be4762008-05-20 16:00:29 +0200190 movw %ax,%bp
wdenk591dda52002-11-18 00:14:45 +0000191o32 cs ljmp *(%bp)
192
193.code32
194protected_mode:
Graeme Russ6dda1312011-12-19 20:00:40 +1100195 /* Reload segment registers */
196 movl $0x18, %eax
197 movw %ax, %fs
198 movw %ax, %ds
199 movw %ax, %gs
200 movw %ax, %es
201 movw %ax, %ss
Wolfgang Denka1be4762008-05-20 16:00:29 +0200202 movl saved_protected_mode_esp, %eax
wdenk591dda52002-11-18 00:14:45 +0000203 movl %eax, %esp
204 popf
205 popa
wdenk57b2d802003-06-27 21:31:46 +0000206 ret
wdenk591dda52002-11-18 00:14:45 +0000207
208temp_eax:
209 .long 0
210
211saved_ss:
Wolfgang Denka1be4762008-05-20 16:00:29 +0200212 .word 0
wdenk591dda52002-11-18 00:14:45 +0000213saved_esp:
214 .long 0
215saved_eax:
216 .long 0
wdenk57b2d802003-06-27 21:31:46 +0000217
wdenk591dda52002-11-18 00:14:45 +0000218realmode_idt_ptr:
wdenk57b2d802003-06-27 21:31:46 +0000219 .word 0x400
220 .word 0x0, 0x0
221
222saved_gdt:
Wolfgang Denka1be4762008-05-20 16:00:29 +0200223 .word 0, 0, 0, 0
wdenk591dda52002-11-18 00:14:45 +0000224saved_idt:
Wolfgang Denka1be4762008-05-20 16:00:29 +0200225 .word 0, 0, 0, 0
wdenk591dda52002-11-18 00:14:45 +0000226
227saved_protected_mode_esp:
Wolfgang Denka1be4762008-05-20 16:00:29 +0200228 .long 0
wdenk57b2d802003-06-27 21:31:46 +0000229
wdenk591dda52002-11-18 00:14:45 +0000230return_ptr:
231 .long protected_mode
232 .word 0x10