Merge branch 'master' of git://www.denx.de/git/u-boot-arm
[platform/kernel/u-boot.git] / lib_i386 / realmode_switch.S
1 /*
2  * (C) Copyright 2002
3  * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
4  *
5  * 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
29  *      e00 ebx;
30  *      e04 ecx;
31  *      e08 edx;
32  *      e0c esi;
33  *      e10 edi;
34  *      e14 ebp;
35  *      e18 eax;
36  *      e1c ds;
37  *      e20 es;
38  *      e24 fs;
39  *      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 */
49 #define o32             .byte 0x66;             /* operand size prefix 32 */
50
51 .section .realmode, "ax"
52 .code16
53                                                 /* 16bit protected mode code here */
54 .globl realmode_enter
55 realmode_enter:
56 o32     pusha
57 o32     pushf
58         cli
59         sidt    saved_idt
60         sgdt    saved_gdt
61         movl    %esp, %eax
62         movl    %eax, saved_protected_mode_esp
63
64         movl    $0x10, %eax
65         movl    %eax, %esp
66         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
73         movl    %cr0, %eax                      /* Go back into real mode by */
74         andl    $0x7ffffffe, %eax               /* clearing PE to 0 */
75         movl    %eax, %cr0
76         ljmp    $0x0,$do_realmode               /* switch to real mode */
77
78 do_realmode:                                    /* realmode code from here */
79         movw    %cs,%ax
80         movw    %ax,%ds
81         movw    %ax,%es
82         movw    %ax,%fs
83         movw    %ax,%gs
84
85                                                 /* create a temporary stack */
86
87         movw    $0xc0, %ax
88         movw    %ax, %ss
89         movw    $0x200, %ax
90         movw    %ax, %sp
91
92         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
110 cs      movw    %ax, temp_ip
111         popl    %eax
112 cs      movw    %ax, temp_cs
113 o32     popf
114         popl    %eax
115         popw    %ss
116         movl    %eax, %esp
117 cs      movl    temp_eax, %eax
118         wbinvd                                  /* self-modifying code,
119                                                  * better flush the cache */
120
121         .byte   0x9a                            /* lcall */
122 temp_ip:
123         .word   0                               /* new ip */
124 temp_cs:
125         .word   0                               /* new cs */
126 realmode_ret:
127                                                 /* save eax, esp and ss */
128 cs      movl    %eax, saved_eax
129         movl    %esp, %eax
130 cs      movl    %eax, saved_esp
131         movw    %ss, %ax
132 cs      movw    %ax, saved_ss
133
134         /* 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 */
137
138         movw    $0xc0, %ax
139         movw    %ax, %ss
140         movw    $0x244, %ax
141         movw    %ax, %sp
142
143         xorl    %eax,%eax
144 cs      movw    saved_ss, %ax
145         pushl   %eax
146 cs      movl    saved_esp, %eax
147         pushl   %eax
148 o32     pushf
149         xorl    %eax,%eax
150 cs      movw    temp_cs, %ax
151         pushl   %eax
152 cs      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
172 o32 cs  lidt    saved_idt
173 o32 cs  lgdt    saved_gdt                       /* Set GDTR */
174
175         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 */
179 next_line:
180         movw    $return_ptr, %ax
181         movw    %ax,%bp
182 o32 cs  ljmp    *(%bp)
183
184 .code32
185 protected_mode:
186         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
193         movl    %eax, %esp
194         popf
195         popa
196         ret
197
198 temp_eax:
199         .long   0
200
201 saved_ss:
202         .word   0
203 saved_esp:
204         .long   0
205 saved_eax:
206         .long   0
207
208 realmode_idt_ptr:
209         .word   0x400
210         .word   0x0, 0x0
211
212 saved_gdt:
213         .word   0, 0, 0, 0
214 saved_idt:
215         .word   0, 0, 0, 0
216
217 saved_protected_mode_esp:
218         .long   0
219
220 return_ptr:
221         .long   protected_mode
222         .word   0x10