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