uboot/arch/x86/cpu/start.S
<<
>>
Prefs
   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