linux/arch/x86/boot/compressed/head_32.S
<<
>>
Prefs
   1/*
   2 *  linux/boot/head.S
   3 *
   4 *  Copyright (C) 1991, 1992, 1993  Linus Torvalds
   5 */
   6
   7/*
   8 *  head.S contains the 32-bit startup code.
   9 *
  10 * NOTE!!! Startup happens at absolute address 0x00001000, which is also where
  11 * the page directory will exist. The startup code will be overwritten by
  12 * the page directory. [According to comments etc elsewhere on a compressed
  13 * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC]
  14 *
  15 * Page 0 is deliberately kept safe, since System Management Mode code in
  16 * laptops may need to access the BIOS data stored there.  This is also
  17 * useful for future device drivers that either access the BIOS via VM86
  18 * mode.
  19 */
  20
  21/*
  22 * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
  23 */
  24        .text
  25
  26#include <linux/init.h>
  27#include <linux/linkage.h>
  28#include <asm/segment.h>
  29#include <asm/page_types.h>
  30#include <asm/boot.h>
  31#include <asm/asm-offsets.h>
  32#include <asm/bootparam.h>
  33
  34/*
  35 * The 32-bit x86 assembler in binutils 2.26 will generate R_386_GOT32X
  36 * relocation to get the symbol address in PIC.  When the compressed x86
  37 * kernel isn't built as PIC, the linker optimizes R_386_GOT32X
  38 * relocations to their fixed symbol addresses.  However, when the
  39 * compressed x86 kernel is loaded at a different address, it leads
  40 * to the following load failure:
  41 *
  42 *   Failed to allocate space for phdrs
  43 *
  44 * during the decompression stage.
  45 *
  46 * If the compressed x86 kernel is relocatable at run-time, it should be
  47 * compiled with -fPIE, instead of -fPIC, if possible and should be built as
  48 * Position Independent Executable (PIE) so that linker won't optimize
  49 * R_386_GOT32X relocation to its fixed symbol address.  Older
  50 * linkers generate R_386_32 relocations against locally defined symbols,
  51 * _bss, _ebss, _got and _egot, in PIE.  It isn't wrong, just less
  52 * optimal than R_386_RELATIVE.  But the x86 kernel fails to properly handle
  53 * R_386_32 relocations when relocating the kernel.  To generate
  54 * R_386_RELATIVE relocations, we mark _bss, _ebss, _got and _egot as
  55 * hidden:
  56 */
  57        .hidden _bss
  58        .hidden _ebss
  59        .hidden _got
  60        .hidden _egot
  61
  62        __HEAD
  63ENTRY(startup_32)
  64#ifdef CONFIG_EFI_STUB
  65        jmp     preferred_addr
  66
  67        /*
  68         * We don't need the return address, so set up the stack so
  69         * efi_main() can find its arguments.
  70         */
  71ENTRY(efi_pe_entry)
  72        add     $0x4, %esp
  73
  74        call    1f
  751:      popl    %esi
  76        subl    $1b, %esi
  77
  78        popl    %ecx
  79        movl    %ecx, efi32_config(%esi)        /* Handle */
  80        popl    %ecx
  81        movl    %ecx, efi32_config+8(%esi)      /* EFI System table pointer */
  82
  83        /* Relocate efi_config->call() */
  84        leal    efi32_config(%esi), %eax
  85        add     %esi, 32(%eax)
  86        pushl   %eax
  87
  88        call    make_boot_params
  89        cmpl    $0, %eax
  90        je      fail
  91        movl    %esi, BP_code32_start(%eax)
  92        popl    %ecx
  93        pushl   %eax
  94        pushl   %ecx
  95        jmp     2f              /* Skip efi_config initialization */
  96
  97ENTRY(efi32_stub_entry)
  98        add     $0x4, %esp
  99        popl    %ecx
 100        popl    %edx
 101
 102        call    1f
 1031:      popl    %esi
 104        subl    $1b, %esi
 105
 106        movl    %ecx, efi32_config(%esi)        /* Handle */
 107        movl    %edx, efi32_config+8(%esi)      /* EFI System table pointer */
 108
 109        /* Relocate efi_config->call() */
 110        leal    efi32_config(%esi), %eax
 111        add     %esi, 32(%eax)
 112        pushl   %eax
 1132:
 114        call    efi_main
 115        cmpl    $0, %eax
 116        movl    %eax, %esi
 117        jne     2f
 118fail:
 119        /* EFI init failed, so hang. */
 120        hlt
 121        jmp     fail
 1222:
 123        movl    BP_code32_start(%esi), %eax
 124        leal    preferred_addr(%eax), %eax
 125        jmp     *%eax
 126
 127preferred_addr:
 128#endif
 129        cld
 130        /*
 131         * Test KEEP_SEGMENTS flag to see if the bootloader is asking
 132         * us to not reload segments
 133         */
 134        testb   $KEEP_SEGMENTS, BP_loadflags(%esi)
 135        jnz     1f
 136
 137        cli
 138        movl    $__BOOT_DS, %eax
 139        movl    %eax, %ds
 140        movl    %eax, %es
 141        movl    %eax, %fs
 142        movl    %eax, %gs
 143        movl    %eax, %ss
 1441:
 145
 146/*
 147 * Calculate the delta between where we were compiled to run
 148 * at and where we were actually loaded at.  This can only be done
 149 * with a short local call on x86.  Nothing  else will tell us what
 150 * address we are running at.  The reserved chunk of the real-mode
 151 * data at 0x1e4 (defined as a scratch field) are used as the stack
 152 * for this calculation. Only 4 bytes are needed.
 153 */
 154        leal    (BP_scratch+4)(%esi), %esp
 155        call    1f
 1561:      popl    %ebp
 157        subl    $1b, %ebp
 158
 159/*
 160 * %ebp contains the address we are loaded at by the boot loader and %ebx
 161 * contains the address where we should move the kernel image temporarily
 162 * for safe in-place decompression.
 163 */
 164
 165#ifdef CONFIG_RELOCATABLE
 166        movl    %ebp, %ebx
 167        movl    BP_kernel_alignment(%esi), %eax
 168        decl    %eax
 169        addl    %eax, %ebx
 170        notl    %eax
 171        andl    %eax, %ebx
 172        cmpl    $LOAD_PHYSICAL_ADDR, %ebx
 173        jge     1f
 174#endif
 175        movl    $LOAD_PHYSICAL_ADDR, %ebx
 1761:
 177
 178        /* Target address to relocate to for decompression */
 179        movl    BP_init_size(%esi), %eax
 180        subl    $_end, %eax
 181        addl    %eax, %ebx
 182
 183        /* Set up the stack */
 184        leal    boot_stack_end(%ebx), %esp
 185
 186        /* Zero EFLAGS */
 187        pushl   $0
 188        popfl
 189
 190/*
 191 * Copy the compressed kernel to the end of our buffer
 192 * where decompression in place becomes safe.
 193 */
 194        pushl   %esi
 195        leal    (_bss-4)(%ebp), %esi
 196        leal    (_bss-4)(%ebx), %edi
 197        movl    $(_bss - startup_32), %ecx
 198        shrl    $2, %ecx
 199        std
 200        rep     movsl
 201        cld
 202        popl    %esi
 203
 204/*
 205 * Jump to the relocated address.
 206 */
 207        leal    relocated(%ebx), %eax
 208        jmp     *%eax
 209ENDPROC(startup_32)
 210
 211        .text
 212relocated:
 213
 214/*
 215 * Clear BSS (stack is currently empty)
 216 */
 217        xorl    %eax, %eax
 218        leal    _bss(%ebx), %edi
 219        leal    _ebss(%ebx), %ecx
 220        subl    %edi, %ecx
 221        shrl    $2, %ecx
 222        rep     stosl
 223
 224/*
 225 * Adjust our own GOT
 226 */
 227        leal    _got(%ebx), %edx
 228        leal    _egot(%ebx), %ecx
 2291:
 230        cmpl    %ecx, %edx
 231        jae     2f
 232        addl    %ebx, (%edx)
 233        addl    $4, %edx
 234        jmp     1b
 2352:
 236
 237/*
 238 * Do the extraction, and jump to the new kernel..
 239 */
 240                                /* push arguments for extract_kernel: */
 241        pushl   $z_output_len   /* decompressed length, end of relocs */
 242
 243        movl    BP_init_size(%esi), %eax
 244        subl    $_end, %eax
 245        movl    %ebx, %ebp
 246        subl    %eax, %ebp
 247        pushl   %ebp            /* output address */
 248
 249        pushl   $z_input_len    /* input_len */
 250        leal    input_data(%ebx), %eax
 251        pushl   %eax            /* input_data */
 252        leal    boot_heap(%ebx), %eax
 253        pushl   %eax            /* heap area */
 254        pushl   %esi            /* real mode pointer */
 255        call    extract_kernel  /* returns kernel location in %eax */
 256        addl    $24, %esp
 257
 258/*
 259 * Jump to the extracted kernel.
 260 */
 261        xorl    %ebx, %ebx
 262        jmp     *%eax
 263
 264#ifdef CONFIG_EFI_STUB
 265        .data
 266efi32_config:
 267        .fill 4,8,0
 268        .long efi_call_phys
 269        .long 0
 270        .byte 0
 271#endif
 272
 273/*
 274 * Stack and heap for uncompression
 275 */
 276        .bss
 277        .balign 4
 278boot_heap:
 279        .fill BOOT_HEAP_SIZE, 1, 0
 280boot_stack:
 281        .fill BOOT_STACK_SIZE, 1, 0
 282boot_stack_end:
 283