xref: /rk3399_rockchip-uboot/arch/x86/cpu/start.S (revision e5aa8a9b1593f524af07318d4e84352b06a53402)
1fea25720SGraeme Russ/*
2fe0c33a5SBin Meng *  U-Boot - x86 Startup Code
3fea25720SGraeme Russ *
4fea25720SGraeme Russ * (C) Copyright 2008-2011
5fea25720SGraeme Russ * Graeme Russ, <graeme.russ@gmail.com>
6fea25720SGraeme Russ *
7fea25720SGraeme Russ * (C) Copyright 2002
8fa82f871SAlbert ARIBAUD * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
9fea25720SGraeme Russ *
101a459660SWolfgang Denk * SPDX-License-Identifier:	GPL-2.0+
11fea25720SGraeme Russ */
12fea25720SGraeme Russ
13fea25720SGraeme Russ#include <config.h>
14fea25720SGraeme Russ#include <asm/global_data.h>
15d1cd0459SSimon Glass#include <asm/post.h>
16109ad143SGraeme Russ#include <asm/processor.h>
17fea25720SGraeme Russ#include <asm/processor-flags.h>
189e6c572fSGraeme Russ#include <generated/generic-asm-offsets.h>
19fe0c33a5SBin Meng#include <generated/asm-offsets.h>
20fea25720SGraeme Russ
21*e5aa8a9bSSimon Glass/*
22*e5aa8a9bSSimon Glass * Define this to boot U-Boot from a 32-bit program which sets the GDT
23*e5aa8a9bSSimon Glass * differently. This can be used to boot directly from any stage of coreboot,
24*e5aa8a9bSSimon Glass * for example, bypassing the normal payload-loading feature.
25*e5aa8a9bSSimon Glass * This is only useful for development.
26*e5aa8a9bSSimon Glass */
27*e5aa8a9bSSimon Glass#undef LOAD_FROM_32_BIT
28*e5aa8a9bSSimon Glass
29fea25720SGraeme Russ.section .text
30fea25720SGraeme Russ.code32
31fea25720SGraeme Russ.globl _start
32fea25720SGraeme Russ.type _start, @function
33fea25720SGraeme Russ.globl _x86boot_start
34fea25720SGraeme Russ_x86boot_start:
35fea25720SGraeme Russ	/*
36da3a95d6SSimon Glass	 * This is the fail-safe 32-bit bootstrap entry point.
37da3a95d6SSimon Glass	 *
38da3a95d6SSimon Glass	 * This code is used when booting from another boot loader like
39da3a95d6SSimon Glass	 * coreboot or EFI. So we repeat some of the same init found in
40da3a95d6SSimon Glass	 * start16.
41fea25720SGraeme Russ	 */
42fea25720SGraeme Russ	cli
43fea25720SGraeme Russ	cld
44fea25720SGraeme Russ
452f0e0cd2SGraeme Russ	/* Turn off cache (this might require a 486-class CPU) */
46fea25720SGraeme Russ	movl	%cr0, %eax
47fea25720SGraeme Russ	orl	$(X86_CR0_NW | X86_CR0_CD), %eax
48fea25720SGraeme Russ	movl	%eax, %cr0
49fea25720SGraeme Russ	wbinvd
50fea25720SGraeme Russ
5191d82a29SGabe Black	/* Tell 32-bit code it is being entered from an in-RAM copy */
5283ec7de3SSimon Glass	movl	$GD_FLG_WARM_BOOT, %ebx
5342fde305SSimon Glass
5442fde305SSimon Glass	/*
5542fde305SSimon Glass	 * Zero the BIST (Built-In Self Test) value since we don't have it.
5642fde305SSimon Glass	 * It must be 0 or the previous loader would have reported an error.
5742fde305SSimon Glass	 */
5842fde305SSimon Glass	movl	$0, %ebp
5942fde305SSimon Glass
6091d82a29SGabe Black	jmp	1f
6183ec7de3SSimon Glass
6283ec7de3SSimon Glass	/* Add a way for tools to discover the _start entry point */
6383ec7de3SSimon Glass	.align	4
6483ec7de3SSimon Glass	.long	0x12345678
65fea25720SGraeme Russ_start:
6691d82a29SGabe Black	/*
67da3a95d6SSimon Glass	 * This is the 32-bit cold-reset entry point, coming from start16.
6883ec7de3SSimon Glass	 * Set %ebx to GD_FLG_COLD_BOOT to indicate this.
6991d82a29SGabe Black	 */
7083ec7de3SSimon Glass	movl	$GD_FLG_COLD_BOOT, %ebx
7142fde305SSimon Glass
72f67cd51eSSimon Glass	/* Save BIST */
73f67cd51eSSimon Glass	movl	%eax, %ebp
7442fde305SSimon Glass1:
7542fde305SSimon Glass
7642fde305SSimon Glass	/* Save table pointer */
7742fde305SSimon Glass	movl	%ecx, %esi
78fea25720SGraeme Russ
79*e5aa8a9bSSimon Glass#ifdef LOAD_FROM_32_BIT
80*e5aa8a9bSSimon Glass	lgdt	gdt_ptr2
81*e5aa8a9bSSimon Glass#endif
82*e5aa8a9bSSimon Glass
83da3a95d6SSimon Glass	/* Load the segement registers to match the GDT loaded in start16.S */
84109ad143SGraeme Russ	movl	$(X86_GDT_ENTRY_32BIT_DS * X86_GDT_ENTRY_SIZE), %eax
85fea25720SGraeme Russ	movw	%ax, %fs
86fea25720SGraeme Russ	movw	%ax, %ds
87fea25720SGraeme Russ	movw	%ax, %gs
88fea25720SGraeme Russ	movw	%ax, %es
89fea25720SGraeme Russ	movw	%ax, %ss
90fea25720SGraeme Russ
9116263087SMike Williams	/* Clear the interrupt vectors */
92fea25720SGraeme Russ	lidt	blank_idt_ptr
93fea25720SGraeme Russ
94da3a95d6SSimon Glass	/*
95da3a95d6SSimon Glass	 * Critical early platform init - generally not used, we prefer init
96da3a95d6SSimon Glass	 * to happen later when we have a console, in case something goes
97da3a95d6SSimon Glass	 * wrong.
98da3a95d6SSimon Glass	 */
99fea25720SGraeme Russ	jmp	early_board_init
100fea25720SGraeme Russ.globl early_board_init_ret
101fea25720SGraeme Russearly_board_init_ret:
102d1cd0459SSimon Glass	post_code(POST_START)
103fea25720SGraeme Russ
104fea25720SGraeme Russ	/* Initialise Cache-As-RAM */
105fea25720SGraeme Russ	jmp	car_init
106fea25720SGraeme Russ.globl car_init_ret
107fea25720SGraeme Russcar_init_ret:
108bceb9f0fSBin Meng#ifndef CONFIG_HAVE_FSP
109fea25720SGraeme Russ	/*
110fea25720SGraeme Russ	 * We now have CONFIG_SYS_CAR_SIZE bytes of Cache-As-RAM (or SRAM,
111fea25720SGraeme Russ	 * or fully initialised SDRAM - we really don't care which)
112fea25720SGraeme Russ	 * starting at CONFIG_SYS_CAR_ADDR to be used as a temporary stack
113da3a95d6SSimon Glass	 * and early malloc() area. The MRC requires some space at the top.
11476f90f30SSimon Glass	 *
11576f90f30SSimon Glass	 * Stack grows down from top of CAR. We have:
11676f90f30SSimon Glass	 *
11776f90f30SSimon Glass	 * top-> CONFIG_SYS_CAR_ADDR + CONFIG_SYS_CAR_SIZE
11865dd74a6SSimon Glass	 *	MRC area
119f0c7d9c7SSimon Glass	 *	global_data with x86 global descriptor table
12076f90f30SSimon Glass	 *	early malloc area
12176f90f30SSimon Glass	 *	stack
12276f90f30SSimon Glass	 * bottom-> CONFIG_SYS_CAR_ADDR
123fea25720SGraeme Russ	 */
12465dd74a6SSimon Glass	movl	$(CONFIG_SYS_CAR_ADDR + CONFIG_SYS_CAR_SIZE - 4), %esp
12565dd74a6SSimon Glass#ifdef CONFIG_DCACHE_RAM_MRC_VAR_SIZE
12665dd74a6SSimon Glass	subl	$CONFIG_DCACHE_RAM_MRC_VAR_SIZE, %esp
12765dd74a6SSimon Glass#endif
128bceb9f0fSBin Meng#else
129bceb9f0fSBin Meng	/*
13048aa6c26SBin Meng	 * U-Boot enters here twice. For the first time it comes from
13148aa6c26SBin Meng	 * car_init_done() with esp points to a temporary stack and esi
13248aa6c26SBin Meng	 * set to zero. For the second time it comes from fsp_init_done()
13348aa6c26SBin Meng	 * with esi holding the HOB list address returned by the FSP.
134bceb9f0fSBin Meng	 */
135bceb9f0fSBin Meng#endif
136f0c7d9c7SSimon Glass	/* Set up global data */
137f0c7d9c7SSimon Glass	mov	%esp, %eax
138ecc30663SAlbert ARIBAUD	call	board_init_f_alloc_reserve
139f0c7d9c7SSimon Glass	mov	%eax, %esp
140ecc30663SAlbert ARIBAUD	call	board_init_f_init_reserve
1418d61625dSGraeme Russ
14260994a02SSimon Glass#ifdef CONFIG_DEBUG_UART
14360994a02SSimon Glass	call	debug_uart_init
14460994a02SSimon Glass#endif
145bbbe55f6SSimon Glass
146f0c7d9c7SSimon Glass	/* Get address of global_data */
147f0c7d9c7SSimon Glass	mov	%fs:0, %edx
148bceb9f0fSBin Meng#ifdef CONFIG_HAVE_FSP
149f0c7d9c7SSimon Glass	/* Store the HOB list if we have one */
150aefaff8eSBin Meng	test	%esi, %esi
151aefaff8eSBin Meng	jz	skip_hob
152f0c7d9c7SSimon Glass	movl	%esi, GD_HOB_LIST(%edx)
153bceb9f0fSBin Meng
15457b10f59SBin Meng	/*
15557b10f59SBin Meng	 * After fsp_init() returns, the stack has already been switched to a
15657b10f59SBin Meng	 * place within system memory as defined by CONFIG_FSP_TEMP_RAM_ADDR.
15757b10f59SBin Meng	 * Enlarge the size of malloc() pool before relocation since we have
15857b10f59SBin Meng	 * plenty of memory now.
15957b10f59SBin Meng	 */
16057b10f59SBin Meng	subl	$CONFIG_FSP_SYS_MALLOC_F_LEN, %esp
16157b10f59SBin Meng	movl	%esp, GD_MALLOC_BASE(%edx)
162aefaff8eSBin Mengskip_hob:
16342fde305SSimon Glass#else
16442fde305SSimon Glass	/* Store table pointer */
165f0c7d9c7SSimon Glass	movl	%esi, GD_TABLE(%edx)
166aefaff8eSBin Meng#endif
167f0c7d9c7SSimon Glass	/* Store BIST */
168f0c7d9c7SSimon Glass	movl	%ebp, GD_BIST(%edx)
1699e6c572fSGraeme Russ
170fea25720SGraeme Russ	/* Set parameter to board_init_f() to boot flags */
171d1cd0459SSimon Glass	post_code(POST_START_DONE)
172fea25720SGraeme Russ	xorl	%eax, %eax
173fea25720SGraeme Russ
174da3a95d6SSimon Glass	/* Enter, U-Boot! */
175fea25720SGraeme Russ	call	board_init_f
176fea25720SGraeme Russ
177fea25720SGraeme Russ	/* indicate (lack of) progress */
178fea25720SGraeme Russ	movw	$0x85, %ax
179fea25720SGraeme Russ	jmp	die
180fea25720SGraeme Russ
181f48dd6fcSGraeme Russ.globl board_init_f_r_trampoline
182f48dd6fcSGraeme Russ.type board_init_f_r_trampoline, @function
183f48dd6fcSGraeme Russboard_init_f_r_trampoline:
184fea25720SGraeme Russ	/*
185fea25720SGraeme Russ	 * SDRAM has been initialised, U-Boot code has been copied into
186fea25720SGraeme Russ	 * RAM, BSS has been cleared and relocation adjustments have been
187fea25720SGraeme Russ	 * made. It is now time to jump into the in-RAM copy of U-Boot
188fea25720SGraeme Russ	 *
189f48dd6fcSGraeme Russ	 * %eax = Address of top of new stack
190fea25720SGraeme Russ	 */
191fea25720SGraeme Russ
1928d61625dSGraeme Russ	/* Stack grows down from top of SDRAM */
193fea25720SGraeme Russ	movl	%eax, %esp
194fea25720SGraeme Russ
195f0c7d9c7SSimon Glass	/* See if we need to disable CAR */
196801d70ceSSimon Glass.weak	car_uninit
197801d70ceSSimon Glass	movl	$car_uninit, %eax
198801d70ceSSimon Glass	cmpl	$0, %eax
199801d70ceSSimon Glass	jz	1f
200801d70ceSSimon Glass
201801d70ceSSimon Glass	call	car_uninit
202801d70ceSSimon Glass1:
203da3a95d6SSimon Glass	/* Re-enter U-Boot by calling board_init_f_r() */
204f48dd6fcSGraeme Russ	call	board_init_f_r
205fea25720SGraeme Russ
2062f0e0cd2SGraeme Russdie:
2072f0e0cd2SGraeme Russ	hlt
208fea25720SGraeme Russ	jmp	die
209fea25720SGraeme Russ	hlt
210fea25720SGraeme Russ
211fea25720SGraeme Russblank_idt_ptr:
212fea25720SGraeme Russ	.word	0		/* limit */
213fea25720SGraeme Russ	.long	0		/* base */
214a206cc23SGraeme Russ
215a206cc23SGraeme Russ	.p2align	2	/* force 4-byte alignment */
216a206cc23SGraeme Russ
217da3a95d6SSimon Glass	/* Add a multiboot header so U-Boot can be loaded by GRUB2 */
218a206cc23SGraeme Russmultiboot_header:
219a206cc23SGraeme Russ	/* magic */
220da3a95d6SSimon Glass	.long	0x1badb002
221a206cc23SGraeme Russ	/* flags */
222a206cc23SGraeme Russ	.long	(1 << 16)
223a206cc23SGraeme Russ	/* checksum */
224a206cc23SGraeme Russ	.long	-0x1BADB002 - (1 << 16)
225a206cc23SGraeme Russ	/* header addr */
226a206cc23SGraeme Russ	.long	multiboot_header - _x86boot_start + CONFIG_SYS_TEXT_BASE
227a206cc23SGraeme Russ	/* load addr */
228a206cc23SGraeme Russ	.long	CONFIG_SYS_TEXT_BASE
229a206cc23SGraeme Russ	/* load end addr */
230a206cc23SGraeme Russ	.long	0
231a206cc23SGraeme Russ	/* bss end addr */
232a206cc23SGraeme Russ	.long	0
233a206cc23SGraeme Russ	/* entry addr */
234a206cc23SGraeme Russ	.long	CONFIG_SYS_TEXT_BASE
235*e5aa8a9bSSimon Glass
236*e5aa8a9bSSimon Glass#ifdef LOAD_FROM_32_BIT
237*e5aa8a9bSSimon Glass	/*
238*e5aa8a9bSSimon Glass	 * The following Global Descriptor Table is just enough to get us into
239*e5aa8a9bSSimon Glass	 * 'Flat Protected Mode' - It will be discarded as soon as the final
240*e5aa8a9bSSimon Glass	 * GDT is setup in a safe location in RAM
241*e5aa8a9bSSimon Glass	 */
242*e5aa8a9bSSimon Glassgdt_ptr2:
243*e5aa8a9bSSimon Glass	.word	0x1f		/* limit (31 bytes = 4 GDT entries - 1) */
244*e5aa8a9bSSimon Glass	.long	gdt_rom2	/* base */
245*e5aa8a9bSSimon Glass
246*e5aa8a9bSSimon Glass	/* Some CPUs are picky about GDT alignment... */
247*e5aa8a9bSSimon Glass	.align	16
248*e5aa8a9bSSimon Glass.globl gdt_rom2
249*e5aa8a9bSSimon Glassgdt_rom2:
250*e5aa8a9bSSimon Glass	/*
251*e5aa8a9bSSimon Glass	 * The GDT table ...
252*e5aa8a9bSSimon Glass	 *
253*e5aa8a9bSSimon Glass	 *	 Selector	Type
254*e5aa8a9bSSimon Glass	 *	 0x00		NULL
255*e5aa8a9bSSimon Glass	 *	 0x08		Unused
256*e5aa8a9bSSimon Glass	 *	 0x10		32bit code
257*e5aa8a9bSSimon Glass	 *	 0x18		32bit data/stack
258*e5aa8a9bSSimon Glass	 */
259*e5aa8a9bSSimon Glass	/* The NULL Desciptor - Mandatory */
260*e5aa8a9bSSimon Glass	.word	0x0000		/* limit_low */
261*e5aa8a9bSSimon Glass	.word	0x0000		/* base_low */
262*e5aa8a9bSSimon Glass	.byte	0x00		/* base_middle */
263*e5aa8a9bSSimon Glass	.byte	0x00		/* access */
264*e5aa8a9bSSimon Glass	.byte	0x00		/* flags + limit_high */
265*e5aa8a9bSSimon Glass	.byte	0x00		/* base_high */
266*e5aa8a9bSSimon Glass
267*e5aa8a9bSSimon Glass	/* Unused Desciptor - (matches Linux) */
268*e5aa8a9bSSimon Glass	.word	0x0000		/* limit_low */
269*e5aa8a9bSSimon Glass	.word	0x0000		/* base_low */
270*e5aa8a9bSSimon Glass	.byte	0x00		/* base_middle */
271*e5aa8a9bSSimon Glass	.byte	0x00		/* access */
272*e5aa8a9bSSimon Glass	.byte	0x00		/* flags + limit_high */
273*e5aa8a9bSSimon Glass	.byte	0x00		/* base_high */
274*e5aa8a9bSSimon Glass
275*e5aa8a9bSSimon Glass	/*
276*e5aa8a9bSSimon Glass	 * The Code Segment Descriptor:
277*e5aa8a9bSSimon Glass	 * - Base   = 0x00000000
278*e5aa8a9bSSimon Glass	 * - Size   = 4GB
279*e5aa8a9bSSimon Glass	 * - Access = Present, Ring 0, Exec (Code), Readable
280*e5aa8a9bSSimon Glass	 * - Flags  = 4kB Granularity, 32-bit
281*e5aa8a9bSSimon Glass	 */
282*e5aa8a9bSSimon Glass	.word	0xffff		/* limit_low */
283*e5aa8a9bSSimon Glass	.word	0x0000		/* base_low */
284*e5aa8a9bSSimon Glass	.byte	0x00		/* base_middle */
285*e5aa8a9bSSimon Glass	.byte	0x9b		/* access */
286*e5aa8a9bSSimon Glass	.byte	0xcf		/* flags + limit_high */
287*e5aa8a9bSSimon Glass	.byte	0x00		/* base_high */
288*e5aa8a9bSSimon Glass
289*e5aa8a9bSSimon Glass	/*
290*e5aa8a9bSSimon Glass	 * The Data Segment Descriptor:
291*e5aa8a9bSSimon Glass	 * - Base   = 0x00000000
292*e5aa8a9bSSimon Glass	 * - Size   = 4GB
293*e5aa8a9bSSimon Glass	 * - Access = Present, Ring 0, Non-Exec (Data), Writable
294*e5aa8a9bSSimon Glass	 * - Flags  = 4kB Granularity, 32-bit
295*e5aa8a9bSSimon Glass	 */
296*e5aa8a9bSSimon Glass	.word	0xffff		/* limit_low */
297*e5aa8a9bSSimon Glass	.word	0x0000		/* base_low */
298*e5aa8a9bSSimon Glass	.byte	0x00		/* base_middle */
299*e5aa8a9bSSimon Glass	.byte	0x93		/* access */
300*e5aa8a9bSSimon Glass	.byte	0xcf		/* flags + limit_high */
301*e5aa8a9bSSimon Glass	.byte	0x00		/* base_high */
302*e5aa8a9bSSimon Glass#endif
303