blob: fce4eccab01e71671efc980a07f4b594fab1cf4d [file] [log] [blame]
wdenk591dda52002-11-18 00:14:45 +00001/*
2 * (C) Copyright 2002
3 * 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
47#define a32 .byte 0x67; /* address size prefix 32 */
wdenk57b2d802003-06-27 21:31:46 +000048#define o32 .byte 0x66; /* operand size prefix 32 */
wdenk591dda52002-11-18 00:14:45 +000049
50.section .realmode, "ax"
51.code16
wdenk591dda52002-11-18 00:14:45 +000052 /* 16bit protected mode code here */
53.globl realmode_enter
54realmode_enter:
55o32 pusha
56o32 pushf
57 cli
Wolfgang Denka1be4762008-05-20 16:00:29 +020058 sidt saved_idt
59 sgdt saved_gdt
60 movl %esp, %eax
61 movl %eax, saved_protected_mode_esp
wdenk57b2d802003-06-27 21:31:46 +000062
wdenk591dda52002-11-18 00:14:45 +000063 movl $0x10, %eax
Wolfgang Denka1be4762008-05-20 16:00:29 +020064 movl %eax, %esp
wdenk591dda52002-11-18 00:14:45 +000065 movw $0x28, %ax
66 movw %ax, %ds
67 movw %ax, %es
68 movw %ax, %fs
69 movw %ax, %gs
70
71 lidt realmode_idt_ptr
Wolfgang Denka1be4762008-05-20 16:00:29 +020072 movl %cr0, %eax /* Go back into real mode by */
73 andl $0x7ffffffe, %eax /* clearing PE to 0 */
wdenk591dda52002-11-18 00:14:45 +000074 movl %eax, %cr0
Wolfgang Denka1be4762008-05-20 16:00:29 +020075 ljmp $0x0,$do_realmode /* switch to real mode */
wdenk57b2d802003-06-27 21:31:46 +000076
77do_realmode: /* realmode code from here */
wdenk591dda52002-11-18 00:14:45 +000078 movw %cs,%ax
79 movw %ax,%ds
80 movw %ax,%es
81 movw %ax,%fs
82 movw %ax,%gs
wdenk57b2d802003-06-27 21:31:46 +000083
wdenk591dda52002-11-18 00:14:45 +000084 /* create a temporary stack */
wdenk57b2d802003-06-27 21:31:46 +000085
86 movw $0xc0, %ax
87 movw %ax, %ss
88 movw $0x200, %ax
89 movw %ax, %sp
90
wdenk591dda52002-11-18 00:14:45 +000091 popl %ebx
92 popl %ecx
93 popl %edx
94 popl %esi
95 popl %edi
96 popl %ebp
97 popl %eax
98 movl %eax, temp_eax
99 popl %eax
100 movw %ax, %ds
101 popl %eax
102 movw %ax, %es
103 popl %eax
104 movw %ax, %fs
105 popl %eax
106 movw %ax, %gs
107 popl %eax /* orig_eax */
108 popl %eax
109cs movw %ax, temp_ip
110 popl %eax
111cs movw %ax, temp_cs
112o32 popf
113 popl %eax
114 popw %ss
115 movl %eax, %esp
116cs movl temp_eax, %eax
Wolfgang Denka1be4762008-05-20 16:00:29 +0200117 wbinvd /* self-modifying code,
wdenk591dda52002-11-18 00:14:45 +0000118 * better flush the cache */
wdenk57b2d802003-06-27 21:31:46 +0000119
wdenk591dda52002-11-18 00:14:45 +0000120 .byte 0x9a /* lcall */
121temp_ip:
Wolfgang Denka1be4762008-05-20 16:00:29 +0200122 .word 0 /* new ip */
wdenk57b2d802003-06-27 21:31:46 +0000123temp_cs:
Wolfgang Denka1be4762008-05-20 16:00:29 +0200124 .word 0 /* new cs */
wdenk591dda52002-11-18 00:14:45 +0000125realmode_ret:
126 /* save eax, esp and ss */
127cs movl %eax, saved_eax
128 movl %esp, %eax
129cs movl %eax, saved_esp
Wolfgang Denka1be4762008-05-20 16:00:29 +0200130 movw %ss, %ax
wdenk591dda52002-11-18 00:14:45 +0000131cs movw %ax, saved_ss
wdenk57b2d802003-06-27 21:31:46 +0000132
wdenk591dda52002-11-18 00:14:45 +0000133 /* restore the stack, note that we set sp to 0x244;
134 * pt_regs is 0x44 bytes long and we push the structure
135 * backwards on to the stack, bottom first */
wdenk57b2d802003-06-27 21:31:46 +0000136
137 movw $0xc0, %ax
138 movw %ax, %ss
139 movw $0x244, %ax
140 movw %ax, %sp
141
wdenk591dda52002-11-18 00:14:45 +0000142 xorl %eax,%eax
143cs movw saved_ss, %ax
144 pushl %eax
145cs movl saved_esp, %eax
146 pushl %eax
147o32 pushf
148 xorl %eax,%eax
149cs movw temp_cs, %ax
150 pushl %eax
151cs movw temp_ip, %ax
152 pushl %eax
153 pushl $0
154 movw %gs, %ax
155 pushl %eax
156 movw %fs, %ax
157 pushl %eax
158 movw %es, %ax
159 pushl %eax
160 movw %ds, %ax
161 pushl %eax
162 movl saved_eax, %eax
163 pushl %eax
164 pushl %ebp
165 pushl %edi
166 pushl %esi
167 pushl %edx
168 pushl %ecx
169 pushl %ebx
170
171o32 cs lidt saved_idt
Wolfgang Denka1be4762008-05-20 16:00:29 +0200172o32 cs lgdt saved_gdt /* Set GDTR */
wdenk591dda52002-11-18 00:14:45 +0000173
Wolfgang Denka1be4762008-05-20 16:00:29 +0200174 movl %cr0, %eax /* Go back into protected mode */
175 orl $1,%eax /* reset PE to 1 */
176 movl %eax, %cr0
177 jmp next_line /* flush prefetch queue */
wdenk57b2d802003-06-27 21:31:46 +0000178next_line:
179 movw $return_ptr, %ax
Wolfgang Denka1be4762008-05-20 16:00:29 +0200180 movw %ax,%bp
wdenk591dda52002-11-18 00:14:45 +0000181o32 cs ljmp *(%bp)
182
183.code32
184protected_mode:
Wolfgang Denka1be4762008-05-20 16:00:29 +0200185 movl $0x18,%eax /* reload GDT[3] */
186 movw %ax,%fs /* reset FS */
187 movw %ax,%ds /* reset DS */
188 movw %ax,%gs /* reset GS */
189 movw %ax,%es /* reset ES */
190 movw %ax,%ss /* reset SS */
191 movl saved_protected_mode_esp, %eax
wdenk591dda52002-11-18 00:14:45 +0000192 movl %eax, %esp
193 popf
194 popa
wdenk57b2d802003-06-27 21:31:46 +0000195 ret
wdenk591dda52002-11-18 00:14:45 +0000196
197temp_eax:
198 .long 0
199
200saved_ss:
Wolfgang Denka1be4762008-05-20 16:00:29 +0200201 .word 0
wdenk591dda52002-11-18 00:14:45 +0000202saved_esp:
203 .long 0
204saved_eax:
205 .long 0
wdenk57b2d802003-06-27 21:31:46 +0000206
wdenk591dda52002-11-18 00:14:45 +0000207realmode_idt_ptr:
wdenk57b2d802003-06-27 21:31:46 +0000208 .word 0x400
209 .word 0x0, 0x0
210
211saved_gdt:
Wolfgang Denka1be4762008-05-20 16:00:29 +0200212 .word 0, 0, 0, 0
wdenk591dda52002-11-18 00:14:45 +0000213saved_idt:
Wolfgang Denka1be4762008-05-20 16:00:29 +0200214 .word 0, 0, 0, 0
wdenk591dda52002-11-18 00:14:45 +0000215
216saved_protected_mode_esp:
Wolfgang Denka1be4762008-05-20 16:00:29 +0200217 .long 0
wdenk57b2d802003-06-27 21:31:46 +0000218
wdenk591dda52002-11-18 00:14:45 +0000219return_ptr:
220 .long protected_mode
221 .word 0x10