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