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