0fa8c11524c6321514f112996470cc35bbfaab25
[coreboot.git] / src / cpu / x86 / 16bit / entry16.inc
1 /*
2  * This software and ancillary information (herein called SOFTWARE)
3  * called LinuxBIOS is made available under the terms described here.
4  *
5  * The SOFTWARE has been approved for release with associated
6  * LA-CC Number 00-34. Unless otherwise indicated, this SOFTWARE has
7  * been authored by an employee or employees of the University of
8  * California, operator of the Los Alamos National Laboratory under
9  * Contract No. W-7405-ENG-36 with the U.S. Department of Energy.
10  *
11  * The U.S. Government has rights to use, reproduce, and distribute this
12  * SOFTWARE. The public may copy, distribute, prepare derivative works
13  * and publicly display this SOFTWARE without charge, provided that this
14  * Notice and any statement of authorship are reproduced on all copies.
15  *
16  * Neither the Government nor the University makes any warranty, express
17  * or implied, or assumes any liability or responsibility for the use of
18  * this SOFTWARE.  If SOFTWARE is modified to produce derivative works,
19  * such modified SOFTWARE should be clearly marked, so as not to confuse
20  * it with the version available from LANL.
21  *
22  * Copyright (C) 2000, Ron Minnich rminnich@lanl.gov
23  *                     Advanced Computing Lab, LANL
24  */
25
26
27 /* Start code to put an i386 or later processor into 32-bit protected mode.
28  */
29
30 #include <arch/rom_segs.h>
31 .code16
32 .globl _start
33 .type _start, @function
34
35 _start:
36         cli
37         /* Save the BIST result */
38         movl    %eax, %ebp
39
40         post_code(POST_RESET_VECTOR_CORRECT)
41
42         /* IMMEDIATELY invalidate the translation lookaside buffer (TLB) before
43          * executing any further code. Even though paging is disabled we
44          * could still get false address translations due to the TLB if we
45          * didn't invalidate it. Thanks to kmliu@sis.com.tw for this TLB fix.
46          */
47
48         xorl    %eax, %eax
49         movl    %eax, %cr3    /* Invalidate TLB*/
50
51         /* Invalidating the cache here seems to be a bad idea on
52          * modern processors.  Don't.
53          * If we are hyperthreaded or we have multiple cores it is bad,
54          * for SMP startup.  On Opterons it causes a 5 second delay.
55          * Invalidating the cache was pure paranoia in any event.
56          * If you cpu needs it you can write a cpu dependent version of
57          * entry16.inc.
58          */
59
60         /* Load an IDT with NULL limit to prevent the 16bit IDT being used
61          * in protected mode before c_start.S sets up a 32bit IDT when entering
62          * ram stage.
63          */
64         movw $nullidt_offset, %bx
65         lidt %cs:(%bx)
66
67         /* Note: gas handles memory addresses in 16 bit code very poorly.
68          * In particular it doesn't appear to have a directive allowing you
69          * associate a section or even an absolute offset with a segment register.
70          *
71          * This means that anything except cs:ip relative offsets are
72          * a real pain in 16 bit mode.  And explains why it is almost
73          * impossible to get gas to do lgdt correctly.
74          *
75          * One way to work around this is to have the linker do the
76          * math instead of the assembler.  This solves the very
77          * pratical problem of being able to write code that can
78          * be relocated.
79          *
80          * An lgdt call before we have memory enabled cannot be
81          * position independent, as we cannot execute a call
82          * instruction to get our current instruction pointer.
83          * So while this code is relocateable it isn't arbitrarily
84          * relocatable.
85          *
86          * The criteria for relocation have been relaxed to their
87          * utmost, so that we can use the same code for both
88          * our initial entry point and startup of the second cpu.
89          * The code assumes when executing at _start that:
90          * (((cs & 0xfff) == 0) and (ip == _start & 0xffff))
91          * or
92          * ((cs == anything) and (ip == 0)).
93          *
94          * The restrictions in reset16.inc mean that _start initially
95          * must be loaded at or above 0xffff0000 or below 0x100000.
96          *
97          * The linker scripts computes gdtptr16_offset by simply returning
98          * the low 16 bits.  This means that the intial segment used
99          * when start is called must be 64K aligned.  This should not
100          * restrict the address as the ip address can be anything.
101          */
102
103         movw    %cs, %ax
104         shlw    $4, %ax
105         movw    $gdtptr16_offset, %bx
106         subw    %ax, %bx
107         data32  lgdt %cs:(%bx)
108
109         movl    %cr0, %eax
110         andl    $0x7FFAFFD1, %eax /* PG,AM,WP,NE,TS,EM,MP = 0 */
111         orl     $0x60000001, %eax /* CD, NW, PE = 1 */
112         movl    %eax, %cr0
113
114         /* Restore BIST to %eax */
115         movl    %ebp, %eax
116
117         /* Now that we are in protected mode jump to a 32 bit code segment. */
118         data32  ljmp    $ROM_CODE_SEG, $__protected_start
119
120         /**
121          * The gdt is defined in entry32.inc, it has a 4 Gb code segment
122          * at 0x08, and a 4 GB data segment at 0x10;
123          */
124 .align  4
125 .globl gdtptr16
126 gdtptr16:
127         .word   gdt_end - gdt -1 /* compute the table limit */
128         .long   gdt              /* we know the offset */
129
130 .align  4
131 .globl nullidt
132 nullidt:
133         .word   0       /* limit */
134         .long   0
135         .word   0
136
137 .globl _estart
138 _estart:
139         .code32
140