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