After this has been brought up many times before, rename src/arch/i386 to
[coreboot.git] / src / arch / x86 / init / entry.S
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 1999 Ronald G. Minnich
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 #include <arch/rom_segs.h>
20         .code16
21         .globl _stage0
22 _stage0:
23         cli
24
25         /* Save the BIST result. */
26         movl    %eax, %ebp;
27
28         /* thanks to kmliu@sis.com.tw for this TLB fix */
29         /* IMMEDIATELY invalidate the translation lookaside buffer (TLB) before
30          * executing any further code. Even though paging is disabled we
31          * could still get false address translations due to the TLB if we
32          * didn't invalidate it.
33          */
34         xorl    %eax, %eax
35         movl    %eax, %cr3      /* Invalidate TLB. */
36
37         /* Switch to protected mode. */
38
39         /* NOTE: With GNU assembler version 2.15.94.0.2.2 (i386-redhat-linux)
40          * using BFD version 2.15.94.0.2.2 20041220 this works fine without all
41          * the ld hackery and other things. So leave it as is with this comment.
42          */
43
44         data32  lgdt %cs:gdtptr
45
46         movl    %cr0, %eax
47         andl    $0x7FFAFFD1, %eax /* PG, AM, WP, NE, TS, EM, MP = 0 */
48         orl     $0x60000001, %eax /* CD, NW, PE = 1 */
49         movl    %eax, %cr0
50
51         /* Restore BIST result. */
52         movl    %ebp, %eax
53
54         // port80_post(0x23)
55         /* Now we are in protected mode. Jump to a 32 bit code segment. */
56         data32  ljmp $ROM_CODE_SEG, $protected_stage0
57
58         /* I am leaving this weird jump in here in the event that future gas
59          * bugs force it to be used.
60          */
61         /* .byte 0x66 */
62         .code32
63         /* ljmp $ROM_CODE_SEG, $protected_stage0 */
64
65         /* .code16 */
66         .align 4
67         .globl gdt16
68 gdt16 = . - _stage0
69 gdt16x:
70         .word   gdt16xend - gdt16x -1   /* Compute the table limit. */
71         .long   gdt16x
72         .word   0
73
74         /* selgdt 0x08, flat code segment */
75         .word   0xffff, 0x0000
76         .byte   0x00, 0x9b, 0xcf, 0x00
77
78         /* selgdt 0x10, flat data segment */
79         .word   0xffff, 0x0000
80         .byte   0x00, 0x93, 0xcf, 0x00
81 gdt16xend:
82
83         /* From now on we are 32 bit. */
84         .code32
85
86         /* We have two gdts where we could have one. That is ok.
87          *
88          * Let's not worry about this -- optimizing gdt is pointless since
89          * we're only in it for a little bit.
90          *
91          * Btw. note the trick below: The GDT points to ITSELF, and the first
92          * good descriptor is at offset 8. So you word-align the table, and
93          * then because you chose 8, you get a nice 64-bit aligned GDT entry,
94          * which is good as this is the size of the entry.
95          * Just in case you ever wonder why people do this.
96          */
97         .align 4
98         .globl gdtptr
99         .globl gdt_limit
100 gdt_limit = gdt_end - gdt - 1           /* Compute the table limit. */
101
102 gdt:
103 gdtptr:
104         .word   gdt_end - gdt -1        /* Compute the table limit. */
105         .long   gdt                     /* We know the offset. */
106         .word   0
107
108         /* selgdt 0x08, flat code segment */
109         .word   0xffff, 0x0000
110         .byte   0x00, 0x9b, 0xcf, 0x00
111
112         /* selgdt 0x10, flat data segment */
113         .word   0xffff, 0x0000
114         .byte   0x00, 0x93, 0xcf, 0x00
115
116 gdt_end:
117
118 /* Reset vector. */
119
120 /*
121  * RVECTOR: Size of reset vector, default is 0x10.
122  * RESRVED: Size of vpd code, default is 0xf0.
123  * BOOTBLK: Size of bootblock code, default is 0x1f00 (8k-256b).
124  */
125
126 SEGMENT_SIZE = 0x10000
127 RVECTOR      = 0x00010
128
129 /* Due to YET ANOTHER BUG in GNU bintools, you can NOT have a code16 here.
130  * I think we should leave it this way forever, as the bugs come and
131  * go -- and come again.
132  *
133  *      .code16
134  *      .section ".rom.text"
135  */
136 .section ".reset", "ax"
137         .globl _resetjump
138 _resetjump:
139         /* GNU bintools bugs again. This jumps to stage0 - 2. Sigh. */
140         /* jmp _stage0 */
141         .byte   0xe9
142         .int    _stage0 - ( . + 2 )
143
144         /* Note: The above jump is hand coded to work around bugs in binutils.
145          * 5 bytes are used for a 3 byte instruction. This works because x86
146          * is little endian and allows us to use supported 32 bit relocations
147          * instead of the weird 16 bit relocations that binutils does not
148          * handle consistenly between versions because they are used so rarely.
149          */