blob: d6c74ecd79b4cea61a5e5b391441b6a11cf512f2 [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
24
25/* 32bit -> 16bit -> 32bit mode switch code */
26
27/*
28 * Stack frame at 0xe00
Wolfgang Denka1be4762008-05-20 16:00:29 +020029 * e00 ebx;
wdenk591dda52002-11-18 00:14:45 +000030 * e04 ecx;
31 * e08 edx;
32 * e0c esi;
33 * e10 edi;
wdenk57b2d802003-06-27 21:31:46 +000034 * e14 ebp;
wdenk591dda52002-11-18 00:14:45 +000035 * e18 eax;
wdenk57b2d802003-06-27 21:31:46 +000036 * e1c ds;
wdenk591dda52002-11-18 00:14:45 +000037 * e20 es;
wdenk57b2d802003-06-27 21:31:46 +000038 * e24 fs;
wdenk591dda52002-11-18 00:14:45 +000039 * e28 gs;
40 * e2c orig_eax;
41 * e30 eip;
42 * e34 cs;
43 * e38 eflags;
44 * e3c esp;
45 * e40 ss;
46 */
47
48#define a32 .byte 0x67; /* address size prefix 32 */
wdenk57b2d802003-06-27 21:31:46 +000049#define o32 .byte 0x66; /* operand size prefix 32 */
wdenk591dda52002-11-18 00:14:45 +000050
51.section .realmode, "ax"
52.code16
wdenk591dda52002-11-18 00:14:45 +000053 /* 16bit protected mode code here */
54.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
Wolfgang Denka1be4762008-05-20 16:00:29 +020073 movl %cr0, %eax /* Go back into real mode by */
74 andl $0x7ffffffe, %eax /* clearing PE to 0 */
wdenk591dda52002-11-18 00:14:45 +000075 movl %eax, %cr0
Wolfgang Denka1be4762008-05-20 16:00:29 +020076 ljmp $0x0,$do_realmode /* switch to real mode */
wdenk57b2d802003-06-27 21:31:46 +000077
78do_realmode: /* realmode code from here */
wdenk591dda52002-11-18 00:14:45 +000079 movw %cs,%ax
80 movw %ax,%ds
81 movw %ax,%es
82 movw %ax,%fs
83 movw %ax,%gs
wdenk57b2d802003-06-27 21:31:46 +000084
wdenk591dda52002-11-18 00:14:45 +000085 /* create a temporary stack */
wdenk57b2d802003-06-27 21:31:46 +000086
87 movw $0xc0, %ax
88 movw %ax, %ss
89 movw $0x200, %ax
90 movw %ax, %sp
91
wdenk591dda52002-11-18 00:14:45 +000092 popl %ebx
93 popl %ecx
94 popl %edx
95 popl %esi
96 popl %edi
97 popl %ebp
98 popl %eax
99 movl %eax, temp_eax
100 popl %eax
101 movw %ax, %ds
102 popl %eax
103 movw %ax, %es
104 popl %eax
105 movw %ax, %fs
106 popl %eax
107 movw %ax, %gs
108 popl %eax /* orig_eax */
109 popl %eax
110cs movw %ax, temp_ip
111 popl %eax
112cs movw %ax, temp_cs
113o32 popf
114 popl %eax
115 popw %ss
116 movl %eax, %esp
117cs movl temp_eax, %eax
Wolfgang Denka1be4762008-05-20 16:00:29 +0200118 wbinvd /* self-modifying code,
wdenk591dda52002-11-18 00:14:45 +0000119 * better flush the cache */
wdenk57b2d802003-06-27 21:31:46 +0000120
wdenk591dda52002-11-18 00:14:45 +0000121 .byte 0x9a /* lcall */
122temp_ip:
Wolfgang Denka1be4762008-05-20 16:00:29 +0200123 .word 0 /* new ip */
wdenk57b2d802003-06-27 21:31:46 +0000124temp_cs:
Wolfgang Denka1be4762008-05-20 16:00:29 +0200125 .word 0 /* new cs */
wdenk591dda52002-11-18 00:14:45 +0000126realmode_ret:
127 /* save eax, esp and ss */
128cs movl %eax, saved_eax
129 movl %esp, %eax
130cs movl %eax, saved_esp
Wolfgang Denka1be4762008-05-20 16:00:29 +0200131 movw %ss, %ax
wdenk591dda52002-11-18 00:14:45 +0000132cs movw %ax, saved_ss
wdenk57b2d802003-06-27 21:31:46 +0000133
wdenk591dda52002-11-18 00:14:45 +0000134 /* restore the stack, note that we set sp to 0x244;
135 * pt_regs is 0x44 bytes long and we push the structure
136 * backwards on to the stack, bottom first */
wdenk57b2d802003-06-27 21:31:46 +0000137
138 movw $0xc0, %ax
139 movw %ax, %ss
140 movw $0x244, %ax
141 movw %ax, %sp
142
wdenk591dda52002-11-18 00:14:45 +0000143 xorl %eax,%eax
144cs movw saved_ss, %ax
145 pushl %eax
146cs movl saved_esp, %eax
147 pushl %eax
148o32 pushf
149 xorl %eax,%eax
150cs movw temp_cs, %ax
151 pushl %eax
152cs movw temp_ip, %ax
153 pushl %eax
154 pushl $0
155 movw %gs, %ax
156 pushl %eax
157 movw %fs, %ax
158 pushl %eax
159 movw %es, %ax
160 pushl %eax
161 movw %ds, %ax
162 pushl %eax
163 movl saved_eax, %eax
164 pushl %eax
165 pushl %ebp
166 pushl %edi
167 pushl %esi
168 pushl %edx
169 pushl %ecx
170 pushl %ebx
171
172o32 cs lidt saved_idt
Wolfgang Denka1be4762008-05-20 16:00:29 +0200173o32 cs lgdt saved_gdt /* Set GDTR */
wdenk591dda52002-11-18 00:14:45 +0000174
Wolfgang Denka1be4762008-05-20 16:00:29 +0200175 movl %cr0, %eax /* Go back into protected mode */
176 orl $1,%eax /* reset PE to 1 */
177 movl %eax, %cr0
178 jmp next_line /* flush prefetch queue */
wdenk57b2d802003-06-27 21:31:46 +0000179next_line:
180 movw $return_ptr, %ax
Wolfgang Denka1be4762008-05-20 16:00:29 +0200181 movw %ax,%bp
wdenk591dda52002-11-18 00:14:45 +0000182o32 cs ljmp *(%bp)
183
184.code32
185protected_mode:
Wolfgang Denka1be4762008-05-20 16:00:29 +0200186 movl $0x18,%eax /* reload GDT[3] */
187 movw %ax,%fs /* reset FS */
188 movw %ax,%ds /* reset DS */
189 movw %ax,%gs /* reset GS */
190 movw %ax,%es /* reset ES */
191 movw %ax,%ss /* reset SS */
192 movl saved_protected_mode_esp, %eax
wdenk591dda52002-11-18 00:14:45 +0000193 movl %eax, %esp
194 popf
195 popa
wdenk57b2d802003-06-27 21:31:46 +0000196 ret
wdenk591dda52002-11-18 00:14:45 +0000197
198temp_eax:
199 .long 0
200
201saved_ss:
Wolfgang Denka1be4762008-05-20 16:00:29 +0200202 .word 0
wdenk591dda52002-11-18 00:14:45 +0000203saved_esp:
204 .long 0
205saved_eax:
206 .long 0
wdenk57b2d802003-06-27 21:31:46 +0000207
wdenk591dda52002-11-18 00:14:45 +0000208realmode_idt_ptr:
wdenk57b2d802003-06-27 21:31:46 +0000209 .word 0x400
210 .word 0x0, 0x0
211
212saved_gdt:
Wolfgang Denka1be4762008-05-20 16:00:29 +0200213 .word 0, 0, 0, 0
wdenk591dda52002-11-18 00:14:45 +0000214saved_idt:
Wolfgang Denka1be4762008-05-20 16:00:29 +0200215 .word 0, 0, 0, 0
wdenk591dda52002-11-18 00:14:45 +0000216
217saved_protected_mode_esp:
Wolfgang Denka1be4762008-05-20 16:00:29 +0200218 .long 0
wdenk57b2d802003-06-27 21:31:46 +0000219
wdenk591dda52002-11-18 00:14:45 +0000220return_ptr:
221 .long protected_mode
222 .word 0x10