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