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 701: 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 98early_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 106car_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 164skip_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 185board_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 206jump_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 216die: 217 hlt 218 jmp die 219 hlt 220 221WEAK(car_uninit) 222 ret 223ENDPROC(car_uninit) 224 225blank_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 */ 232multiboot_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_SYS_TEXT_BASE 241 /* load addr */ 242 .long CONFIG_SYS_TEXT_BASE 243 /* load end addr */ 244 .long 0 245 /* bss end addr */ 246 .long 0 247 /* entry addr */ 248 .long CONFIG_SYS_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 */ 256gdt_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 263gdt_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 317