Prepare v2023.10
[platform/kernel/u-boot.git] / arch / x86 / cpu / start.S
1 /* SPDX-License-Identifier: GPL-2.0+ */
2 /*
3  *  U-Boot - x86 Startup Code
4  *
5  * This is always the first code to run from the U-Boot source. To spell it out:
6  *
7  * 1. When TPL (Tertiary Program Loader) is enabled, the boot flow is
8  * TPL->SPL->U-Boot and this file is used for TPL. Then start_from_tpl.S is used
9  * for SPL and start_from_spl.S is used for U-Boot proper.
10  *
11  * 2. When SPL (Secondary Program Loader) is enabled, but not TPL, the boot
12  * flow is SPL->U-Boot and this file is used for SPL. Then start_from_spl.S is
13  * used for U-Boot proper.
14  *
15  * 3. When neither TPL nor SPL is used, this file is used for U-Boot proper.
16  *
17  * (C) Copyright 2008-2011
18  * Graeme Russ, <graeme.russ@gmail.com>
19  *
20  * (C) Copyright 2002
21  * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
22  */
23
24 #include <config.h>
25 #include <asm/post.h>
26 #include <asm/processor.h>
27 #include <asm/processor-flags.h>
28 #include <generated/generic-asm-offsets.h>
29 #include <generated/asm-offsets.h>
30 #include <linux/linkage.h>
31
32 .section .text.start
33 .code32
34 .globl _start
35 .type _start, @function
36 .globl _x86boot_start
37 _x86boot_start:
38         /*
39          * This is the fail-safe 32-bit bootstrap entry point.
40          *
41          * This code is used when booting from another boot loader like
42          * coreboot or EFI. So we repeat some of the same init found in
43          * start16.
44          */
45         cli
46         cld
47
48         /* Turn off cache (this might require a 486-class CPU) */
49         movl    %cr0, %eax
50         orl     $(X86_CR0_NW | X86_CR0_CD), %eax
51         movl    %eax, %cr0
52         wbinvd
53
54         /*
55          * Zero the BIST (Built-In Self Test) value since we don't have it.
56          * It must be 0 or the previous loader would have reported an error.
57          */
58         movl    $0, %ebp
59
60         jmp     1f
61
62         /* Add a way for tools to discover the _start entry point */
63         .align  4
64         .long   0x12345678
65 _start:
66         /* This is the 32-bit cold-reset entry point, coming from start16 */
67
68         /* Save BIST */
69         movl    %eax, %ebp
70 1:
71
72         /* Save table pointer */
73         movl    %ecx, %esi
74
75 #ifdef CONFIG_X86_LOAD_FROM_32_BIT
76         lgdt    gdt_ptr2
77 #endif
78
79         /* Load the segment registers to match the GDT loaded in start16.S */
80         movl    $(X86_GDT_ENTRY_32BIT_DS * X86_GDT_ENTRY_SIZE), %eax
81         movw    %ax, %fs
82         movw    %ax, %ds
83         movw    %ax, %gs
84         movw    %ax, %es
85         movw    %ax, %ss
86
87         /* Clear the interrupt vectors */
88         lidt    blank_idt_ptr
89
90 #ifdef CONFIG_USE_EARLY_BOARD_INIT
91         /*
92          * Critical early platform init - generally not used, we prefer init
93          * to happen later when we have a console, in case something goes
94          * wrong.
95          */
96         jmp     early_board_init
97 .globl early_board_init_ret
98 early_board_init_ret:
99 #endif
100
101         post_code(POST_START)
102
103         /* Initialise Cache-As-RAM */
104         jmp     car_init
105 .globl car_init_ret
106 car_init_ret:
107 #ifdef CONFIG_USE_CAR
108         /*
109          * We now have CONFIG_SYS_CAR_SIZE bytes of Cache-As-RAM (or SRAM,
110          * or fully initialised SDRAM - we really don't care which)
111          * starting at CONFIG_SYS_CAR_ADDR to be used as a temporary stack
112          * and early malloc() area. The MRC requires some space at the top.
113          *
114          * Stack grows down from top of CAR. We have:
115          *
116          * top-> CONFIG_SYS_CAR_ADDR + CONFIG_SYS_CAR_SIZE
117          *      MRC area
118          *      global_data with x86 global descriptor table
119          *      early malloc area
120          *      stack
121          * bottom-> CONFIG_SYS_CAR_ADDR
122          */
123         movl    $(CONFIG_SYS_CAR_ADDR + CONFIG_SYS_CAR_SIZE - 4), %esp
124 #ifdef CONFIG_DCACHE_RAM_MRC_VAR_SIZE
125         subl    $CONFIG_DCACHE_RAM_MRC_VAR_SIZE, %esp
126 #endif
127 #else
128         /*
129          * Instructions for FSP1, but not FSP2:
130          * U-Boot enters here twice. For the first time it comes from
131          * car_init_done() with esp points to a temporary stack and esi
132          * set to zero. For the second time it comes from fsp_init_done()
133          * with esi holding the HOB list address returned by the FSP.
134          */
135 #endif
136         /* Set up global data */
137         mov     %esp, %eax
138         call    board_init_f_alloc_reserve
139         mov     %eax, %esp
140         call    board_init_f_init_reserve
141
142 #ifdef CONFIG_DEBUG_UART
143         call    debug_uart_init
144 #endif
145
146         /* Get address of global_data */
147         mov     %fs:0, %edx
148 #if defined(CONFIG_USE_HOB) && !defined(CONFIG_USE_CAR)
149         /* Store the HOB list if we have one */
150         test    %esi, %esi
151         jz      skip_hob
152         movl    %esi, GD_HOB_LIST(%edx)
153
154 #ifdef CONFIG_HAVE_FSP
155         /*
156          * After fsp_init() returns, the stack has already been switched to a
157          * place within system memory as defined by CONFIG_FSP_TEMP_RAM_ADDR.
158          * Enlarge the size of malloc() pool before relocation since we have
159          * plenty of memory now.
160          */
161         subl    $CONFIG_FSP_SYS_MALLOC_F_LEN, %esp
162         movl    %esp, GD_MALLOC_BASE(%edx)
163 #endif
164 skip_hob:
165 #else
166         /* Store table pointer */
167         movl    %esi, GD_TABLE(%edx)
168 #endif
169         /* Store BIST */
170         movl    %ebp, GD_BIST(%edx)
171
172         /* Set parameter to board_init_f() to boot flags */
173         post_code(POST_START_DONE)
174         xorl    %eax, %eax
175
176         /* Enter, U-Boot! */
177         call    board_init_f
178
179         /* indicate (lack of) progress */
180         movw    $0x85, %ax
181         jmp     die
182
183 .globl board_init_f_r_trampoline
184 .type board_init_f_r_trampoline, @function
185 board_init_f_r_trampoline:
186         /*
187          * SDRAM has been initialised, U-Boot code has been copied into
188          * RAM, BSS has been cleared and relocation adjustments have been
189          * made. It is now time to jump into the in-RAM copy of U-Boot
190          *
191          * %eax = Address of top of new stack
192          */
193
194         /* Stack grows down from top of SDRAM */
195         movl    %eax, %esp
196
197         /* See if we need to disable CAR */
198         call    car_uninit
199
200         /* Re-enter U-Boot by calling board_init_f_r() */
201         call    board_init_f_r
202
203 #ifdef CONFIG_TPL
204 .globl jump_to_spl
205 .type jump_to_spl, @function
206 jump_to_spl:
207         /* Reset stack to the top of CAR space */
208         movl    $(CONFIG_SYS_CAR_ADDR + CONFIG_SYS_CAR_SIZE - 4), %esp
209 #ifdef CONFIG_DCACHE_RAM_MRC_VAR_SIZE
210         subl    $CONFIG_DCACHE_RAM_MRC_VAR_SIZE, %esp
211 #endif
212
213         jmp     *%eax
214 #endif
215
216 die:
217         hlt
218         jmp     die
219         hlt
220
221 WEAK(car_uninit)
222         ret
223 ENDPROC(car_uninit)
224
225 blank_idt_ptr:
226         .word   0               /* limit */
227         .long   0               /* base */
228
229         .p2align        2       /* force 4-byte alignment */
230
231         /* Add a multiboot header so U-Boot can be loaded by GRUB2 */
232 multiboot_header:
233         /* magic */
234         .long   0x1badb002
235         /* flags */
236         .long   (1 << 16)
237         /* checksum */
238         .long   -0x1BADB002 - (1 << 16)
239         /* header addr */
240         .long   multiboot_header - _x86boot_start + CONFIG_TEXT_BASE
241         /* load addr */
242         .long   CONFIG_TEXT_BASE
243         /* load end addr */
244         .long   0
245         /* bss end addr */
246         .long   0
247         /* entry addr */
248         .long   CONFIG_TEXT_BASE
249
250 #ifdef CONFIG_X86_LOAD_FROM_32_BIT
251         /*
252          * The following Global Descriptor Table is just enough to get us into
253          * 'Flat Protected Mode' - It will be discarded as soon as the final
254          * GDT is setup in a safe location in RAM
255          */
256 gdt_ptr2:
257         .word   0x1f            /* limit (31 bytes = 4 GDT entries - 1) */
258         .long   gdt_rom2        /* base */
259
260         /* Some CPUs are picky about GDT alignment... */
261         .align  16
262 .globl gdt_rom2
263 gdt_rom2:
264         /*
265          * The GDT table ...
266          *
267          *       Selector       Type
268          *       0x00           NULL
269          *       0x08           Unused
270          *       0x10           32bit code
271          *       0x18           32bit data/stack
272          */
273         /* The NULL Desciptor - Mandatory */
274         .word   0x0000          /* limit_low */
275         .word   0x0000          /* base_low */
276         .byte   0x00            /* base_middle */
277         .byte   0x00            /* access */
278         .byte   0x00            /* flags + limit_high */
279         .byte   0x00            /* base_high */
280
281         /* Unused Desciptor - (matches Linux) */
282         .word   0x0000          /* limit_low */
283         .word   0x0000          /* base_low */
284         .byte   0x00            /* base_middle */
285         .byte   0x00            /* access */
286         .byte   0x00            /* flags + limit_high */
287         .byte   0x00            /* base_high */
288
289         /*
290          * The Code Segment Descriptor:
291          * - Base   = 0x00000000
292          * - Size   = 4GB
293          * - Access = Present, Ring 0, Exec (Code), Readable
294          * - Flags  = 4kB Granularity, 32-bit
295          */
296         .word   0xffff          /* limit_low */
297         .word   0x0000          /* base_low */
298         .byte   0x00            /* base_middle */
299         .byte   0x9b            /* access */
300         .byte   0xcf            /* flags + limit_high */
301         .byte   0x00            /* base_high */
302
303         /*
304          * The Data Segment Descriptor:
305          * - Base   = 0x00000000
306          * - Size   = 4GB
307          * - Access = Present, Ring 0, Non-Exec (Data), Writable
308          * - Flags  = 4kB Granularity, 32-bit
309          */
310         .word   0xffff          /* limit_low */
311         .word   0x0000          /* base_low */
312         .byte   0x00            /* base_middle */
313         .byte   0x93            /* access */
314         .byte   0xcf            /* flags + limit_high */
315         .byte   0x00            /* base_high */
316 #endif