[FREELDR]
[reactos.git] / reactos / boot / freeldr / freeldr / arch / i386 / entry.S
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2002 Brian Palmer <brianp@sginet.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <asm.inc>
21 #include <arch/pc/x86common.h>
22
23 EXTERN _BootMain:PROC
24 EXTERN _InitIdt:PROC
25 EXTERN _i386Idt:DWORD
26 //EXTERN _i386idtptr:FWORD
27
28 .code32
29
30 PUBLIC _RealEntryPoint
31 _RealEntryPoint:
32
33 /* Setup segment selectors */
34 mov ax, PMODE_DS
35 mov ds, ax
36 mov es, ax
37 mov fs, ax
38 mov gs, ax
39 mov ss, ax
40
41 /* Setup protected mode stack */
42 mov esp, dword ptr [stack32]
43
44 /* Load the IDT */
45 #ifdef _USE_ML
46 lidt fword ptr [i386idtptr]
47 #else
48 lidt i386idtptr
49 #endif
50
51 /* Continue execution */
52 jmp dword ptr [ContinueAddress]
53
54 ContinueAddress:
55 .long _FrldrStartup
56
57
58 _FrldrStartup:
59
60 /* Store BootDrive and BootPartition */
61 xor eax, eax
62 mov al, dl
63 mov dword ptr [_FrldrBootDrive], eax
64 mov al, dh
65 mov dword ptr [_FrldrBootPartition], eax
66
67 /* Patch long jump with real mode entry point */
68 mov eax, dword ptr ds:[BSS_RealModeEntry]
69 mov dword ptr ds:[SwitchToReal16Address], eax
70
71 /* Initialize the idt */
72 call _InitIdt
73
74 /* GO! */
75 xor eax, eax
76 push eax
77 call _BootMain
78
79 /* We should never get here */
80 stop:
81 jmp stop
82 nop
83 nop
84
85 #ifndef _USE_ML
86 /*
87 * Switches the processor to protected mode
88 * it destroys eax
89 */
90 EXTERN(switch_to_prot)
91
92 .code16
93
94 cli /* None of these */
95
96 /* We don't know what values are currently */
97 /* in the segment registers. So we are */
98 /* going to reload them with sane values. */
99 /* Of course CS has to already be valid. */
100 /* We are currently in real-mode so we */
101 /* need real-mode segment values. */
102 xor ax, ax
103 mov ds, ax
104 mov es, ax
105 mov fs, ax
106 mov gs, ax
107 mov ss, ax
108
109 /* Get the return address off the stack */
110 pop word ptr ds:[code32ret]
111
112 /* Save 16-bit stack pointer */
113 mov word ptr ds:[stack16], sp
114
115 /* Load the GDT */
116 lgdt gdtptr
117
118 /* Load the IDT */
119 lidt i386idtptr
120
121 /* Enable Protected Mode */
122 mov eax, cr0
123 or eax, CR0_PE_SET
124 mov cr0, eax
125
126 /* Clear prefetch queue & correct CS */
127 //ljmp PMODE_CS, inpmode
128 jmp far ptr PMODE_CS:inpmode
129
130 .code32
131
132 inpmode:
133 /* Setup segment selectors */
134 mov ax, PMODE_DS
135 mov ds, ax
136 mov es, ax
137 mov fs, ax
138 mov gs, ax
139 mov ss, ax
140 mov esp, dword ptr [stack32]
141
142 /* Put the return address back onto the stack */
143 push dword ptr [code32ret]
144
145 /* Now return in p-mode! */
146 ret
147
148 /*
149 * Switches the processor back to real mode
150 * it destroys eax
151 */
152 EXTERN(switch_to_real)
153
154 .code32
155
156 /* We don't know what values are currently */
157 /* in the segment registers. So we are */
158 /* going to reload them with sane values. */
159 /* Of course CS has to already be valid. */
160 /* We are currently in protected-mode so we */
161 /* need protected-mode segment values. */
162 mov ax, PMODE_DS
163 mov ds, ax
164 mov es, ax
165 mov fs, ax
166 mov gs, ax
167 mov ss, ax
168
169 /* Get the return address off the stack */
170 pop dword ptr [code16ret]
171
172 /* Save 32-bit stack pointer */
173 mov dword ptr [stack32], esp
174
175 /* jmp to 16-bit segment to set the limit correctly */
176 ljmp RMODE_CS, switch_to_real16
177
178 switch_to_real16:
179 .code16
180
181 /* Restore segment registers to correct limit */
182 mov ax, RMODE_DS
183 mov ds, ax
184 mov es, ax
185 mov fs, ax
186 mov gs, ax
187 mov ss, ax
188
189 /* Disable Protected Mode */
190 mov eax, cr0
191 and eax, CR0_PE_CLR
192 mov cr0, eax
193
194 /* Clear prefetch queue & correct CS */
195 //ljmp $0, $inrmode
196 jmp far ptr 0:inrmode
197
198 inrmode:
199 mov ax, cs
200 mov ds, ax
201 mov es, ax
202 mov fs, ax
203 mov gs, ax
204 mov ss, ax
205
206 /* Clear out the high 16-bits of ESP */
207 /* This is needed because I have one */
208 /* machine that hangs when booted to dos if */
209 /* anything other than 0x0000 is in the high */
210 /* 16-bits of ESP. Even though real-mode */
211 /* code should only use SP and not ESP. */
212 xor esp, esp
213
214 mov sp, word ptr ds:[stack16]
215
216 /* Put the return address back onto the stack */
217 push word ptr ds:[code16ret]
218
219 /* Load IDTR with real mode value */
220 lidt rmode_idtptr
221
222 sti /* These are ok now */
223
224 /* Now return in r-mode! */
225 ret
226 #endif
227
228 .code32
229
230 Int386_regsin:
231 .long 0
232 Int386_regsout:
233 .long 0
234
235 /*
236 * int Int386(int ivec, REGS* in, REGS* out);
237 */
238 PUBLIC _Int386
239 _Int386:
240
241 /* Get the function parameters */
242 mov eax, dword ptr [esp + 4]
243 mov dword ptr ds:[BSS_IntVector], eax
244 mov eax, dword ptr [esp + 8]
245 mov dword ptr [Int386_regsin], eax
246 mov eax, dword ptr [esp + 12]
247 mov dword ptr [Int386_regsout], eax
248
249 /* Save all registers + segment registers */
250 push ds
251 push es
252 push fs
253 push gs
254 pusha
255
256 /* Copy input registers */
257 mov esi, dword ptr [Int386_regsin]
258 mov edi, BSS_RegisterSet
259 mov ecx, 9
260 rep movsd
261
262 /* Set the callback index */
263 mov bx, 0
264
265 /* Set continue address and switch to real mode */
266 mov dword ptr [ContinueAddress], offset Int386_return
267 jmp SwitchToReal
268
269 Int386_return:
270
271 /* Copy output registers */
272 mov esi, BSS_RegisterSet
273 mov edi, dword ptr [Int386_regsout]
274 mov ecx, 9
275 rep movsd
276
277 popa
278 pop gs
279 pop fs
280 pop es
281 pop ds
282 ret
283
284
285 SwitchToReal:
286 /* Set sane segments */
287 mov ax, PMODE_DS
288 mov ds, ax
289 mov es, ax
290 mov fs, ax
291 mov gs, ax
292 mov ss, ax
293
294 /* Save 32-bit stack pointer */
295 mov dword ptr [stack32], esp
296
297 /* jmp to 16-bit segment to set the limit correctly */
298 .byte HEX(0ea) // jmp far RMODE_CS:switch_to_real16
299 SwitchToReal16Address:
300 .long 0 // receives address of switch_to_real16
301 .word RMODE_CS
302 nop
303
304
305 /* 16-bit stack pointer */
306 stack16:
307 .word STACK16ADDR
308
309 /* 32-bit stack pointer */
310 stack32:
311 .long STACK32ADDR
312
313 /* 16-bit return address */
314 code16ret:
315 .long 0
316
317 /* 32-bit return address */
318 code32ret:
319 .long 0
320
321
322 .align 4 /* force 4-byte alignment */
323 gdt:
324 /* NULL Descriptor */
325 .word HEX(0000)
326 .word HEX(0000)
327 .word HEX(0000)
328 .word HEX(0000)
329
330 /* 32-bit flat CS */
331 .word HEX(FFFF)
332 .word HEX(0000)
333 .word HEX(9A00)
334 .word HEX(00CF)
335
336 /* 32-bit flat DS */
337 .word HEX(FFFF)
338 .word HEX(0000)
339 .word HEX(9200)
340 .word HEX(00CF)
341
342 /* 16-bit real mode CS */
343 .word HEX(FFFF)
344 .word HEX(0000)
345 .word HEX(9E00)
346 .word HEX(0000)
347
348 /* 16-bit real mode DS */
349 .word HEX(FFFF)
350 .word HEX(0000)
351 .word HEX(9200)
352 .word HEX(0000)
353
354 /* GDT table pointer */
355 gdtptr:
356 .word HEX(27) /* Limit */
357 .long gdt /* Base Address */
358
359 /* Real-mode IDT pointer */
360 rmode_idtptr:
361 .word HEX(3ff) /* Limit */
362 .long 0 /* Base Address */
363
364 PUBLIC i386idtptr
365 i386idtptr:
366 .word 255 /* Limit */
367 .long _i386Idt /* Base Address */
368
369 PUBLIC _FrldrBootDrive
370 _FrldrBootDrive:
371 .long 0
372
373 PUBLIC _FrldrBootPartition
374 _FrldrBootPartition:
375 .long 0
376
377 END