xref: /rk3399_rockchip-uboot/arch/x86/cpu/start.S (revision 446d4e048ee3b00f7907e15cd02aa404cc714c77)
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
21fea25720SGraeme Russ.section .text
22fea25720SGraeme Russ.code32
23fea25720SGraeme Russ.globl _start
24fea25720SGraeme Russ.type _start, @function
25fea25720SGraeme Russ.globl _x86boot_start
26fea25720SGraeme Russ_x86boot_start:
27fea25720SGraeme Russ	/*
28da3a95d6SSimon Glass	 * This is the fail-safe 32-bit bootstrap entry point.
29da3a95d6SSimon Glass	 *
30da3a95d6SSimon Glass	 * This code is used when booting from another boot loader like
31da3a95d6SSimon Glass	 * coreboot or EFI. So we repeat some of the same init found in
32da3a95d6SSimon Glass	 * start16.
33fea25720SGraeme Russ	 */
34fea25720SGraeme Russ	cli
35fea25720SGraeme Russ	cld
36fea25720SGraeme Russ
372f0e0cd2SGraeme Russ	/* Turn off cache (this might require a 486-class CPU) */
38fea25720SGraeme Russ	movl	%cr0, %eax
39fea25720SGraeme Russ	orl	$(X86_CR0_NW | X86_CR0_CD), %eax
40fea25720SGraeme Russ	movl	%eax, %cr0
41fea25720SGraeme Russ	wbinvd
42fea25720SGraeme Russ
4391d82a29SGabe Black	/* Tell 32-bit code it is being entered from an in-RAM copy */
4483ec7de3SSimon Glass	movl	$GD_FLG_WARM_BOOT, %ebx
4542fde305SSimon Glass
4642fde305SSimon Glass	/*
4742fde305SSimon Glass	 * Zero the BIST (Built-In Self Test) value since we don't have it.
4842fde305SSimon Glass	 * It must be 0 or the previous loader would have reported an error.
4942fde305SSimon Glass	 */
5042fde305SSimon Glass	movl	$0, %ebp
5142fde305SSimon Glass
5291d82a29SGabe Black	jmp	1f
5383ec7de3SSimon Glass
5483ec7de3SSimon Glass	/* Add a way for tools to discover the _start entry point */
5583ec7de3SSimon Glass	.align	4
5683ec7de3SSimon Glass	.long	0x12345678
57fea25720SGraeme Russ_start:
5891d82a29SGabe Black	/*
59da3a95d6SSimon Glass	 * This is the 32-bit cold-reset entry point, coming from start16.
6083ec7de3SSimon Glass	 * Set %ebx to GD_FLG_COLD_BOOT to indicate this.
6191d82a29SGabe Black	 */
6283ec7de3SSimon Glass	movl	$GD_FLG_COLD_BOOT, %ebx
6342fde305SSimon Glass
64f67cd51eSSimon Glass	/* Save BIST */
65f67cd51eSSimon Glass	movl	%eax, %ebp
6642fde305SSimon Glass1:
6742fde305SSimon Glass
6842fde305SSimon Glass	/* Save table pointer */
6942fde305SSimon Glass	movl	%ecx, %esi
70fea25720SGraeme Russ
71*446d4e04SAndy Shevchenko#ifdef CONFIG_X86_LOAD_FROM_32_BIT
72e5aa8a9bSSimon Glass	lgdt	gdt_ptr2
73e5aa8a9bSSimon Glass#endif
74e5aa8a9bSSimon Glass
75da3a95d6SSimon Glass	/* Load the segement registers to match the GDT loaded in start16.S */
76109ad143SGraeme Russ	movl	$(X86_GDT_ENTRY_32BIT_DS * X86_GDT_ENTRY_SIZE), %eax
77fea25720SGraeme Russ	movw	%ax, %fs
78fea25720SGraeme Russ	movw	%ax, %ds
79fea25720SGraeme Russ	movw	%ax, %gs
80fea25720SGraeme Russ	movw	%ax, %es
81fea25720SGraeme Russ	movw	%ax, %ss
82fea25720SGraeme Russ
8316263087SMike Williams	/* Clear the interrupt vectors */
84fea25720SGraeme Russ	lidt	blank_idt_ptr
85fea25720SGraeme Russ
86da3a95d6SSimon Glass	/*
87da3a95d6SSimon Glass	 * Critical early platform init - generally not used, we prefer init
88da3a95d6SSimon Glass	 * to happen later when we have a console, in case something goes
89da3a95d6SSimon Glass	 * wrong.
90da3a95d6SSimon Glass	 */
91fea25720SGraeme Russ	jmp	early_board_init
92fea25720SGraeme Russ.globl early_board_init_ret
93fea25720SGraeme Russearly_board_init_ret:
94d1cd0459SSimon Glass	post_code(POST_START)
95fea25720SGraeme Russ
96fea25720SGraeme Russ	/* Initialise Cache-As-RAM */
97fea25720SGraeme Russ	jmp	car_init
98fea25720SGraeme Russ.globl car_init_ret
99fea25720SGraeme Russcar_init_ret:
100bceb9f0fSBin Meng#ifndef CONFIG_HAVE_FSP
101fea25720SGraeme Russ	/*
102fea25720SGraeme Russ	 * We now have CONFIG_SYS_CAR_SIZE bytes of Cache-As-RAM (or SRAM,
103fea25720SGraeme Russ	 * or fully initialised SDRAM - we really don't care which)
104fea25720SGraeme Russ	 * starting at CONFIG_SYS_CAR_ADDR to be used as a temporary stack
105da3a95d6SSimon Glass	 * and early malloc() area. The MRC requires some space at the top.
10676f90f30SSimon Glass	 *
10776f90f30SSimon Glass	 * Stack grows down from top of CAR. We have:
10876f90f30SSimon Glass	 *
10976f90f30SSimon Glass	 * top-> CONFIG_SYS_CAR_ADDR + CONFIG_SYS_CAR_SIZE
11065dd74a6SSimon Glass	 *	MRC area
111f0c7d9c7SSimon Glass	 *	global_data with x86 global descriptor table
11276f90f30SSimon Glass	 *	early malloc area
11376f90f30SSimon Glass	 *	stack
11476f90f30SSimon Glass	 * bottom-> CONFIG_SYS_CAR_ADDR
115fea25720SGraeme Russ	 */
11665dd74a6SSimon Glass	movl	$(CONFIG_SYS_CAR_ADDR + CONFIG_SYS_CAR_SIZE - 4), %esp
11765dd74a6SSimon Glass#ifdef CONFIG_DCACHE_RAM_MRC_VAR_SIZE
11865dd74a6SSimon Glass	subl	$CONFIG_DCACHE_RAM_MRC_VAR_SIZE, %esp
11965dd74a6SSimon Glass#endif
120bceb9f0fSBin Meng#else
121bceb9f0fSBin Meng	/*
12248aa6c26SBin Meng	 * U-Boot enters here twice. For the first time it comes from
12348aa6c26SBin Meng	 * car_init_done() with esp points to a temporary stack and esi
12448aa6c26SBin Meng	 * set to zero. For the second time it comes from fsp_init_done()
12548aa6c26SBin Meng	 * with esi holding the HOB list address returned by the FSP.
126bceb9f0fSBin Meng	 */
127bceb9f0fSBin Meng#endif
128f0c7d9c7SSimon Glass	/* Set up global data */
129f0c7d9c7SSimon Glass	mov	%esp, %eax
130ecc30663SAlbert ARIBAUD	call	board_init_f_alloc_reserve
131f0c7d9c7SSimon Glass	mov	%eax, %esp
132ecc30663SAlbert ARIBAUD	call	board_init_f_init_reserve
1338d61625dSGraeme Russ
13460994a02SSimon Glass#ifdef CONFIG_DEBUG_UART
13560994a02SSimon Glass	call	debug_uart_init
13660994a02SSimon Glass#endif
137bbbe55f6SSimon Glass
138f0c7d9c7SSimon Glass	/* Get address of global_data */
139f0c7d9c7SSimon Glass	mov	%fs:0, %edx
140bceb9f0fSBin Meng#ifdef CONFIG_HAVE_FSP
141f0c7d9c7SSimon Glass	/* Store the HOB list if we have one */
142aefaff8eSBin Meng	test	%esi, %esi
143aefaff8eSBin Meng	jz	skip_hob
144f0c7d9c7SSimon Glass	movl	%esi, GD_HOB_LIST(%edx)
145bceb9f0fSBin Meng
14657b10f59SBin Meng	/*
14757b10f59SBin Meng	 * After fsp_init() returns, the stack has already been switched to a
14857b10f59SBin Meng	 * place within system memory as defined by CONFIG_FSP_TEMP_RAM_ADDR.
14957b10f59SBin Meng	 * Enlarge the size of malloc() pool before relocation since we have
15057b10f59SBin Meng	 * plenty of memory now.
15157b10f59SBin Meng	 */
15257b10f59SBin Meng	subl	$CONFIG_FSP_SYS_MALLOC_F_LEN, %esp
15357b10f59SBin Meng	movl	%esp, GD_MALLOC_BASE(%edx)
154aefaff8eSBin Mengskip_hob:
15542fde305SSimon Glass#else
15642fde305SSimon Glass	/* Store table pointer */
157f0c7d9c7SSimon Glass	movl	%esi, GD_TABLE(%edx)
158aefaff8eSBin Meng#endif
159f0c7d9c7SSimon Glass	/* Store BIST */
160f0c7d9c7SSimon Glass	movl	%ebp, GD_BIST(%edx)
1619e6c572fSGraeme Russ
162fea25720SGraeme Russ	/* Set parameter to board_init_f() to boot flags */
163d1cd0459SSimon Glass	post_code(POST_START_DONE)
164fea25720SGraeme Russ	xorl	%eax, %eax
165fea25720SGraeme Russ
166da3a95d6SSimon Glass	/* Enter, U-Boot! */
167fea25720SGraeme Russ	call	board_init_f
168fea25720SGraeme Russ
169fea25720SGraeme Russ	/* indicate (lack of) progress */
170fea25720SGraeme Russ	movw	$0x85, %ax
171fea25720SGraeme Russ	jmp	die
172fea25720SGraeme Russ
173f48dd6fcSGraeme Russ.globl board_init_f_r_trampoline
174f48dd6fcSGraeme Russ.type board_init_f_r_trampoline, @function
175f48dd6fcSGraeme Russboard_init_f_r_trampoline:
176fea25720SGraeme Russ	/*
177fea25720SGraeme Russ	 * SDRAM has been initialised, U-Boot code has been copied into
178fea25720SGraeme Russ	 * RAM, BSS has been cleared and relocation adjustments have been
179fea25720SGraeme Russ	 * made. It is now time to jump into the in-RAM copy of U-Boot
180fea25720SGraeme Russ	 *
181f48dd6fcSGraeme Russ	 * %eax = Address of top of new stack
182fea25720SGraeme Russ	 */
183fea25720SGraeme Russ
1848d61625dSGraeme Russ	/* Stack grows down from top of SDRAM */
185fea25720SGraeme Russ	movl	%eax, %esp
186fea25720SGraeme Russ
187f0c7d9c7SSimon Glass	/* See if we need to disable CAR */
188801d70ceSSimon Glass.weak	car_uninit
189801d70ceSSimon Glass	movl	$car_uninit, %eax
190801d70ceSSimon Glass	cmpl	$0, %eax
191801d70ceSSimon Glass	jz	1f
192801d70ceSSimon Glass
193801d70ceSSimon Glass	call	car_uninit
194801d70ceSSimon Glass1:
195da3a95d6SSimon Glass	/* Re-enter U-Boot by calling board_init_f_r() */
196f48dd6fcSGraeme Russ	call	board_init_f_r
197fea25720SGraeme Russ
1982f0e0cd2SGraeme Russdie:
1992f0e0cd2SGraeme Russ	hlt
200fea25720SGraeme Russ	jmp	die
201fea25720SGraeme Russ	hlt
202fea25720SGraeme Russ
203fea25720SGraeme Russblank_idt_ptr:
204fea25720SGraeme Russ	.word	0		/* limit */
205fea25720SGraeme Russ	.long	0		/* base */
206a206cc23SGraeme Russ
207a206cc23SGraeme Russ	.p2align	2	/* force 4-byte alignment */
208a206cc23SGraeme Russ
209da3a95d6SSimon Glass	/* Add a multiboot header so U-Boot can be loaded by GRUB2 */
210a206cc23SGraeme Russmultiboot_header:
211a206cc23SGraeme Russ	/* magic */
212da3a95d6SSimon Glass	.long	0x1badb002
213a206cc23SGraeme Russ	/* flags */
214a206cc23SGraeme Russ	.long	(1 << 16)
215a206cc23SGraeme Russ	/* checksum */
216a206cc23SGraeme Russ	.long	-0x1BADB002 - (1 << 16)
217a206cc23SGraeme Russ	/* header addr */
218a206cc23SGraeme Russ	.long	multiboot_header - _x86boot_start + CONFIG_SYS_TEXT_BASE
219a206cc23SGraeme Russ	/* load addr */
220a206cc23SGraeme Russ	.long	CONFIG_SYS_TEXT_BASE
221a206cc23SGraeme Russ	/* load end addr */
222a206cc23SGraeme Russ	.long	0
223a206cc23SGraeme Russ	/* bss end addr */
224a206cc23SGraeme Russ	.long	0
225a206cc23SGraeme Russ	/* entry addr */
226a206cc23SGraeme Russ	.long	CONFIG_SYS_TEXT_BASE
227e5aa8a9bSSimon Glass
228*446d4e04SAndy Shevchenko#ifdef CONFIG_X86_LOAD_FROM_32_BIT
229e5aa8a9bSSimon Glass	/*
230e5aa8a9bSSimon Glass	 * The following Global Descriptor Table is just enough to get us into
231e5aa8a9bSSimon Glass	 * 'Flat Protected Mode' - It will be discarded as soon as the final
232e5aa8a9bSSimon Glass	 * GDT is setup in a safe location in RAM
233e5aa8a9bSSimon Glass	 */
234e5aa8a9bSSimon Glassgdt_ptr2:
235e5aa8a9bSSimon Glass	.word	0x1f		/* limit (31 bytes = 4 GDT entries - 1) */
236e5aa8a9bSSimon Glass	.long	gdt_rom2	/* base */
237e5aa8a9bSSimon Glass
238e5aa8a9bSSimon Glass	/* Some CPUs are picky about GDT alignment... */
239e5aa8a9bSSimon Glass	.align	16
240e5aa8a9bSSimon Glass.globl gdt_rom2
241e5aa8a9bSSimon Glassgdt_rom2:
242e5aa8a9bSSimon Glass	/*
243e5aa8a9bSSimon Glass	 * The GDT table ...
244e5aa8a9bSSimon Glass	 *
245e5aa8a9bSSimon Glass	 *	 Selector	Type
246e5aa8a9bSSimon Glass	 *	 0x00		NULL
247e5aa8a9bSSimon Glass	 *	 0x08		Unused
248e5aa8a9bSSimon Glass	 *	 0x10		32bit code
249e5aa8a9bSSimon Glass	 *	 0x18		32bit data/stack
250e5aa8a9bSSimon Glass	 */
251e5aa8a9bSSimon Glass	/* The NULL Desciptor - Mandatory */
252e5aa8a9bSSimon Glass	.word	0x0000		/* limit_low */
253e5aa8a9bSSimon Glass	.word	0x0000		/* base_low */
254e5aa8a9bSSimon Glass	.byte	0x00		/* base_middle */
255e5aa8a9bSSimon Glass	.byte	0x00		/* access */
256e5aa8a9bSSimon Glass	.byte	0x00		/* flags + limit_high */
257e5aa8a9bSSimon Glass	.byte	0x00		/* base_high */
258e5aa8a9bSSimon Glass
259e5aa8a9bSSimon Glass	/* Unused Desciptor - (matches Linux) */
260e5aa8a9bSSimon Glass	.word	0x0000		/* limit_low */
261e5aa8a9bSSimon Glass	.word	0x0000		/* base_low */
262e5aa8a9bSSimon Glass	.byte	0x00		/* base_middle */
263e5aa8a9bSSimon Glass	.byte	0x00		/* access */
264e5aa8a9bSSimon Glass	.byte	0x00		/* flags + limit_high */
265e5aa8a9bSSimon Glass	.byte	0x00		/* base_high */
266e5aa8a9bSSimon Glass
267e5aa8a9bSSimon Glass	/*
268e5aa8a9bSSimon Glass	 * The Code Segment Descriptor:
269e5aa8a9bSSimon Glass	 * - Base   = 0x00000000
270e5aa8a9bSSimon Glass	 * - Size   = 4GB
271e5aa8a9bSSimon Glass	 * - Access = Present, Ring 0, Exec (Code), Readable
272e5aa8a9bSSimon Glass	 * - Flags  = 4kB Granularity, 32-bit
273e5aa8a9bSSimon Glass	 */
274e5aa8a9bSSimon Glass	.word	0xffff		/* limit_low */
275e5aa8a9bSSimon Glass	.word	0x0000		/* base_low */
276e5aa8a9bSSimon Glass	.byte	0x00		/* base_middle */
277e5aa8a9bSSimon Glass	.byte	0x9b		/* access */
278e5aa8a9bSSimon Glass	.byte	0xcf		/* flags + limit_high */
279e5aa8a9bSSimon Glass	.byte	0x00		/* base_high */
280e5aa8a9bSSimon Glass
281e5aa8a9bSSimon Glass	/*
282e5aa8a9bSSimon Glass	 * The Data Segment Descriptor:
283e5aa8a9bSSimon Glass	 * - Base   = 0x00000000
284e5aa8a9bSSimon Glass	 * - Size   = 4GB
285e5aa8a9bSSimon Glass	 * - Access = Present, Ring 0, Non-Exec (Data), Writable
286e5aa8a9bSSimon Glass	 * - Flags  = 4kB Granularity, 32-bit
287e5aa8a9bSSimon Glass	 */
288e5aa8a9bSSimon Glass	.word	0xffff		/* limit_low */
289e5aa8a9bSSimon Glass	.word	0x0000		/* base_low */
290e5aa8a9bSSimon Glass	.byte	0x00		/* base_middle */
291e5aa8a9bSSimon Glass	.byte	0x93		/* access */
292e5aa8a9bSSimon Glass	.byte	0xcf		/* flags + limit_high */
293e5aa8a9bSSimon Glass	.byte	0x00		/* base_high */
294e5aa8a9bSSimon Glass#endif
295