* clean up all but two warnings on artecgroup dbe61
[coreboot.git] / src / devices / oprom / x86_asm.S
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2009 coresystems GmbH
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
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
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19
20 #define REALMODE_BASE           0x600
21 #define RELOCATED(x)    (x - __realmode_code + REALMODE_BASE)
22
23 /* CR0 bits */
24 #define PE              (1 << 0)
25
26 /* This is the intXX interrupt handler stub code. It gets copied
27  * to the IDT and to some fixed addresses in the F segment. Before
28  * the code can used, it gets patched up by the C function copying 
29  * it: byte 3 (the $0 in movb $0, %al) is overwritten with the int#.
30  */
31
32         .code16
33         .globl __idt_handler
34 __idt_handler:
35         pushal
36         movb    $0, %al /* This instruction gets modified */
37         ljmp    $0, $__interrupt_handler_16bit
38         .globl __idt_handler_size
39 __idt_handler_size = ( . - __idt_handler)
40
41
42 /* In order to be independent of coreboot's position in RAM
43  * we relocate a part of the code to the low megabyte, so the
44  * CPU can use it in real-mode. This code lives at __realmode_code.
45  */
46         .globl __realmode_code
47 __realmode_code:
48
49 /* Realmode IDT pointer structure. */
50         .globl __realmode_idt
51 __realmode_idt = RELOCATED(.)
52         .word 1023      /* 16-bit limit */
53         .long 0         /* 24-bit base */
54         .word 0
55
56 /* Preserve old stack */
57 __stack = RELOCATED(.)
58         .long 0
59
60         .code32
61         .globl __run_optionrom
62 __run_optionrom = RELOCATED(.)
63         /* save all registers to the stack */
64         pushal
65
66         /* Move the protected mode stack to a safe place */
67         mov     %esp, __stack
68
69         /* Get devfn into %ecx */
70         movl    %esp, %ebp
71         /* This function is called with regparm=0 and we have
72          * to skip the 32 byte from pushal:
73          */
74         movl    36(%ebp), %ecx
75
76         /* Activate the right segment descriptor real mode. */
77         ljmp    $0x28, $RELOCATED(1f)
78 1:
79 .code16
80         /* 16 bit code from here on... */
81
82         /* Load the segment registers w/ properly configured
83          * segment descriptors. They will retain these
84          * configurations (limits, writability, etc.) once
85          * protected mode is turned off.
86          */
87         mov     $0x30, %ax
88         mov     %ax, %ds       
89         mov     %ax, %es       
90         mov     %ax, %fs       
91         mov     %ax, %gs       
92         mov     %ax, %ss       
93
94         /* Turn off protection */
95         movl    %cr0, %eax
96         andl    $~PE, %eax
97         movl    %eax, %cr0
98
99         /* Now really going into real mode */
100         ljmp    $0, $RELOCATED(1f)
101 1:
102         /* Setup a stack: Put the stack at the end of page zero.
103          * That way we can easily share it between real and
104          * protected, since the 16-bit ESP at segment 0 will
105          * work for any case. */
106         mov     $0x0, %ax
107         mov     %ax, %ss
108         movl    $0x1000, %eax
109         movl    %eax, %esp
110
111         /* Load our 16 bit idt */
112         xor     %ax, %ax
113         mov     %ax, %ds
114         lidt    __realmode_idt
115
116         /* Set all segments to 0x0000, ds to 0x0040 */
117         mov     %ax, %es       
118         mov     %ax, %fs       
119         mov     %ax, %gs       
120         mov     $0x40, %ax
121         mov     %ax, %ds
122         mov     %cx, %ax        // restore ax
123
124         /* ************************************ */
125         // TODO this will not work for non-VGA option ROMs
126         /* run VGA BIOS at 0xc000:0003 */
127         lcall   $0xc000, $0x0003
128         /* ************************************ */
129
130         /* If we got here, just about done.
131          * Need to get back to protected mode
132          */
133         movl    %cr0, %eax
134         orl     $PE, %eax
135         movl    %eax, %cr0
136
137         /* Now that we are in protected mode
138          * jump to a 32 bit code segment.
139          */
140         data32  ljmp    $0x10, $RELOCATED(1f)
141 1:
142         .code32
143         movw    $0x18, %ax     
144         mov     %ax, %ds       
145         mov     %ax, %es
146         mov     %ax, %fs
147         mov     %ax, %gs
148         mov     %ax, %ss
149
150         /* restore proper idt */
151         lidt    idtarg
152
153         /* and exit */
154         mov     __stack, %esp
155         popal
156         ret
157
158 #if defined(CONFIG_GEODE_VSA) && CONFIG_GEODE_VSA
159 #define VSA2_ENTRY_POINT        0x60020
160
161         .globl __run_vsa
162 __run_vsa = RELOCATED(.)
163         /* save all registers to the stack */
164         pushal
165
166         /* Move the protected mode stack to a safe place */
167         mov     %esp, __stack
168
169         movl    %esp, %ebp
170         /* This function is called with regparm=0 and we have
171          * to skip the 32 byte from pushal:
172          */
173         movl    36(%ebp), %ecx
174         movl    40(%ebp), %edx
175
176         /* Activate the right segment descriptor real mode. */
177         ljmp    $0x28, $RELOCATED(1f)
178 1:
179 .code16
180         /* 16 bit code from here on... */
181
182         /* Load the segment registers w/ properly configured
183          * segment descriptors. They will retain these
184          * configurations (limits, writability, etc.) once
185          * protected mode is turned off.
186          */
187         mov     $0x30, %ax
188         mov     %ax, %ds       
189         mov     %ax, %es       
190         mov     %ax, %fs       
191         mov     %ax, %gs       
192         mov     %ax, %ss       
193
194         /* Turn off protection */
195         movl    %cr0, %eax
196         andl    $~PE, %eax
197         movl    %eax, %cr0
198
199         /* Now really going into real mode */
200         ljmp    $0, $RELOCATED(1f)
201 1:
202         /* Setup a stack: Put the stack at the end of page zero.
203          * That way we can easily share it between real and
204          * protected, since the 16-bit ESP at segment 0 will
205          * work for any case. */
206         mov     $0x0, %ax
207         mov     %ax, %ss
208         movl    $0x1000, %eax
209         movl    %eax, %esp
210
211         /* Load our 16 bit idt */
212         xor     %ax, %ax
213         mov     %ax, %ds
214         lidt    __realmode_idt
215
216         /* Set all segments to 0x0000, ds to 0x0040 */
217         mov     %ax, %es       
218         mov     %ax, %fs       
219         mov     %ax, %gs       
220         mov     $0x40, %ax
221         mov     %ax, %ds
222         mov     %cx, %ax        // restore ax
223
224         /* ************************************ */
225         lcall   $((VSA2_ENTRY_POINT & 0xffff0000) >> 4), $(VSA2_ENTRY_POINT & 0xffff)
226         /* ************************************ */
227
228         /* If we got here, just about done.
229          * Need to get back to protected mode
230          */
231         movl    %cr0, %eax
232         orl     $PE, %eax
233         movl    %eax, %cr0
234
235         /* Now that we are in protected mode
236          * jump to a 32 bit code segment.
237          */
238         data32  ljmp    $0x10, $RELOCATED(1f)
239 1:
240         .code32
241         movw    $0x18, %ax     
242         mov     %ax, %ds       
243         mov     %ax, %es
244         mov     %ax, %fs
245         mov     %ax, %gs
246         mov     %ax, %ss
247
248         /* restore proper idt */
249         lidt    idtarg
250
251         /* and exit */
252         mov     __stack, %esp
253         popal
254         ret
255 #endif
256
257         .globl __run_interrupt
258 __run_interrupt = RELOCATED(.)
259
260         /* paranoia -- does ecx get saved? not sure. This is
261          * the easiest safe thing to do. */
262         pushal
263         /* save the stack */
264         mov     %esp, __stack
265
266
267         /*  This configures CS properly for real mode. */
268         ljmp    $0x28, $RELOCATED(1f)
269 1:
270         .code16 /* 16 bit code from here on... */
271
272         // DEBUG
273         movb    $0xec, %al
274         outb    %al, $0x80
275
276         /* Load the segment registers w/ properly configured segment
277          * descriptors.  They will retain these configurations (limits,
278          * writability, etc.) once protected mode is turned off.
279          */
280         mov     $0x30, %ax     
281         mov     %ax, %ds       
282         mov     %ax, %es       
283         mov     %ax, %fs       
284         mov     %ax, %gs       
285         mov     %ax, %ss       
286
287         /* Turn off protected mode */
288         movl    %cr0, %eax     
289         andl    $~PE, %eax
290         movl    %eax, %cr0     
291
292         /* Now really going into real mode */
293         data32 ljmp     $0, $RELOCATED(1f)
294 1:
295
296         /* put the stack at the end of page zero.
297          * that way we can easily share it between real and protected,
298          * since the 16-bit ESP at segment 0 will work for any case.
299          */
300         /* setup a stack */
301         mov     $0x0, %ax
302         mov     %ax, %ss
303         movl    $0x1000, %eax
304         movl    %eax, %esp
305
306         /* Load 16-bit intXX IDT */
307         xor     %ax, %ax       
308         mov     %ax, %ds
309         lidt    __realmode_idt
310
311         /* Set all segments to 0x0000 */
312         mov     %ax, %ds
313         mov     %ax, %es
314         mov     %ax, %fs
315         mov     %ax, %gs
316
317         /* Call VGA BIOS int10 function 0x4f14 to enable main console
318          * Epia-M does not always autosence the main console so forcing
319          * it on is good.
320          */
321
322         /* Ask VGA option rom to enable main console */
323         movw    $0x4f14,%ax
324         movw    $0x8003,%bx
325         movw    $1, %cx
326         movw    $0, %dx
327         movw    $0, %di
328         int     $0x10
329
330         /* Ok, the job is done, now go back to protected mode coreboot */
331         movl    %cr0, %eax
332         orl     $PE, %eax
333         movl    %eax, %cr0
334
335         /* Now that we are in protected mode jump to a 32-bit code segment. */
336         data32  ljmp    $0x10, $RELOCATED(1f)
337 1:
338         .code32
339         movw    $0x18, %ax
340         mov     %ax, %ds
341         mov     %ax, %es
342         mov     %ax, %fs
343         mov     %ax, %gs
344         mov     %ax, %ss
345
346         /* restore coreboot's 32-bit IDT */
347         lidt    idtarg
348
349         /* Exit */
350         mov     __stack, %esp
351         popal
352         ret
353
354 /* This is the 16-bit interrupt entry point called by the IDT stub code.
355  * Before this code code is called, %eax is pushed to the stack, and the
356  * interrupt number is loaded into %al
357  */
358         .code16
359 __interrupt_handler_16bit = RELOCATED(.)
360         push    %ds
361         push    %es
362         push    %fs
363         push    %gs
364
365         /* Clean up the interrupt number. We could have done this in the stub,
366          * but it would have cost 2 more bytes per stub entry.
367          */
368         andl    $0xff, %eax
369         pushl   %eax            /* ... and make it the first parameter */
370
371         /* Switch to protected mode */
372         movl    %cr0, %eax
373         orl     $PE, %eax
374         movl    %eax, %cr0
375
376         /* ... and jump to a 32 bit code segment. */
377         data32 ljmp    $0x10, $RELOCATED(1f)
378 1:
379         .code32
380         movw    $0x18, %ax
381         mov     %ax, %ds
382         mov     %ax, %es
383         mov     %ax, %fs
384         mov     %ax, %gs
385         mov     %ax, %ss
386
387         lidt    idtarg
388
389         /* Call the C interrupt handler */
390         movl    $interrupt_handler, %eax
391         call    *%eax
392
393         /* Now return to real mode ... */
394         ljmp    $0x28, $RELOCATED(1f)
395 1:
396         .code16
397         /* Load the segment registers with properly configured segment
398          * descriptors.  They will retain these configurations (limits,
399          * writability, etc.) once protected mode is turned off.
400          */
401         mov     $0x30, %ax
402         mov     %ax, %ds
403         mov     %ax, %es
404         mov     %ax, %fs
405         mov     %ax, %gs
406         mov     %ax, %ss
407
408         /* Disable Protected Mode */
409         movl    %cr0, %eax
410         andl    $~PE, %eax
411         movl    %eax, %cr0
412
413         /* Now really going into real mode */
414         ljmp $0,  $RELOCATED(1f)
415 1:
416         /* Restore real-mode stack segment */
417         mov     $0x0, %ax
418         mov     %ax, %ss
419
420         /* Restore 16-bit IDT */
421         xor     %ax, %ax
422         mov     %ax, %ds
423         lidt    __realmode_idt
424
425         /* Set up our segment registers to segment 0x0000 */
426         mov     %ax, %es
427         mov     %ax, %fs
428         mov     %ax, %gs
429         mov     $0x40, %ax
430         mov     %ax, %ds
431
432         /* Restore all registers, including those
433          * manipulated by the C handler
434          */
435         popl    %eax
436         pop     %gs
437         pop     %fs
438         pop     %es
439         pop     %ds
440         popal
441         iret
442
443         .globl __realmode_code_size
444 __realmode_code_size = (. - __realmode_code)
445
446         .code32