linux/arch/x86/boot/compressed/head_32.S
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2/*
   3 *  linux/boot/head.S
   4 *
   5 *  Copyright (C) 1991, 1992, 1993  Linus Torvalds
   6 */
   7
   8/*
   9 *  head.S contains the 32-bit startup code.
  10 *
  11 * NOTE!!! Startup happens at absolute address 0x00001000, which is also where
  12 * the page directory will exist. The startup code will be overwritten by
  13 * the page directory. [According to comments etc elsewhere on a compressed
  14 * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC]
  15 *
  16 * Page 0 is deliberately kept safe, since System Management Mode code in
  17 * laptops may need to access the BIOS data stored there.  This is also
  18 * useful for future device drivers that either access the BIOS via VM86
  19 * mode.
  20 */
  21
  22/*
  23 * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
  24 */
  25        .text
  26
  27#include <linux/init.h>
  28#include <linux/linkage.h>
  29#include <asm/segment.h>
  30#include <asm/page_types.h>
  31#include <asm/boot.h>
  32#include <asm/asm-offsets.h>
  33#include <asm/bootparam.h>
  34
  35/*
  36 * The 32-bit x86 assembler in binutils 2.26 will generate R_386_GOT32X
  37 * relocation to get the symbol address in PIC.  When the compressed x86
  38 * kernel isn't built as PIC, the linker optimizes R_386_GOT32X
  39 * relocations to their fixed symbol addresses.  However, when the
  40 * compressed x86 kernel is loaded at a different address, it leads
  41 * to the following load failure:
  42 *
  43 *   Failed to allocate space for phdrs
  44 *
  45 * during the decompression stage.
  46 *
  47 * If the compressed x86 kernel is relocatable at run-time, it should be
  48 * compiled with -fPIE, instead of -fPIC, if possible and should be built as
  49 * Position Independent Executable (PIE) so that linker won't optimize
  50 * R_386_GOT32X relocation to its fixed symbol address.  Older
  51 * linkers generate R_386_32 relocations against locally defined symbols,
  52 * _bss, _ebss, _got and _egot, in PIE.  It isn't wrong, just less
  53 * optimal than R_386_RELATIVE.  But the x86 kernel fails to properly handle
  54 * R_386_32 relocations when relocating the kernel.  To generate
  55 * R_386_RELATIVE relocations, we mark _bss, _ebss, _got and _egot as
  56 * hidden:
  57 */
  58        .hidden _bss
  59        .hidden _ebss
  60        .hidden _got
  61        .hidden _egot
  62
  63        __HEAD
  64ENTRY(startup_32)
  65        cld
  66        /*
  67         * Test KEEP_SEGMENTS flag to see if the bootloader is asking
  68         * us to not reload segments
  69         */
  70        testb   $KEEP_SEGMENTS, BP_loadflags(%esi)
  71        jnz     1f
  72
  73        cli
  74        movl    $__BOOT_DS, %eax
  75        movl    %eax, %ds
  76        movl    %eax, %es
  77        movl    %eax, %fs
  78        movl    %eax, %gs
  79        movl    %eax, %ss
  801:
  81
  82/*
  83 * Calculate the delta between where we were compiled to run
  84 * at and where we were actually loaded at.  This can only be done
  85 * with a short local call on x86.  Nothing  else will tell us what
  86 * address we are running at.  The reserved chunk of the real-mode
  87 * data at 0x1e4 (defined as a scratch field) are used as the stack
  88 * for this calculation. Only 4 bytes are needed.
  89 */
  90        leal    (BP_scratch+4)(%esi), %esp
  91        call    1f
  921:      popl    %ebp
  93        subl    $1b, %ebp
  94
  95/*
  96 * %ebp contains the address we are loaded at by the boot loader and %ebx
  97 * contains the address where we should move the kernel image temporarily
  98 * for safe in-place decompression.
  99 */
 100
 101#ifdef CONFIG_RELOCATABLE
 102        movl    %ebp, %ebx
 103        movl    BP_kernel_alignment(%esi), %eax
 104        decl    %eax
 105        addl    %eax, %ebx
 106        notl    %eax
 107        andl    %eax, %ebx
 108        cmpl    $LOAD_PHYSICAL_ADDR, %ebx
 109        jge     1f
 110#endif
 111        movl    $LOAD_PHYSICAL_ADDR, %ebx
 1121:
 113
 114        /* Target address to relocate to for decompression */
 115        movl    BP_init_size(%esi), %eax
 116        subl    $_end, %eax
 117        addl    %eax, %ebx
 118
 119        /* Set up the stack */
 120        leal    boot_stack_end(%ebx), %esp
 121
 122        /* Zero EFLAGS */
 123        pushl   $0
 124        popfl
 125
 126/*
 127 * Copy the compressed kernel to the end of our buffer
 128 * where decompression in place becomes safe.
 129 */
 130        pushl   %esi
 131        leal    (_bss-4)(%ebp), %esi
 132        leal    (_bss-4)(%ebx), %edi
 133        movl    $(_bss - startup_32), %ecx
 134        shrl    $2, %ecx
 135        std
 136        rep     movsl
 137        cld
 138        popl    %esi
 139
 140/*
 141 * Jump to the relocated address.
 142 */
 143        leal    relocated(%ebx), %eax
 144        jmp     *%eax
 145ENDPROC(startup_32)
 146
 147#ifdef CONFIG_EFI_STUB
 148/*
 149 * We don't need the return address, so set up the stack so efi_main() can find
 150 * its arguments.
 151 */
 152ENTRY(efi_pe_entry)
 153        add     $0x4, %esp
 154
 155        call    1f
 1561:      popl    %esi
 157        subl    $1b, %esi
 158
 159        popl    %ecx
 160        movl    %ecx, efi32_config(%esi)        /* Handle */
 161        popl    %ecx
 162        movl    %ecx, efi32_config+8(%esi)      /* EFI System table pointer */
 163
 164        /* Relocate efi_config->call() */
 165        leal    efi32_config(%esi), %eax
 166        add     %esi, 40(%eax)
 167        pushl   %eax
 168
 169        call    make_boot_params
 170        cmpl    $0, %eax
 171        je      fail
 172        movl    %esi, BP_code32_start(%eax)
 173        popl    %ecx
 174        pushl   %eax
 175        pushl   %ecx
 176        jmp     2f              /* Skip efi_config initialization */
 177ENDPROC(efi_pe_entry)
 178
 179ENTRY(efi32_stub_entry)
 180        add     $0x4, %esp
 181        popl    %ecx
 182        popl    %edx
 183
 184        call    1f
 1851:      popl    %esi
 186        subl    $1b, %esi
 187
 188        movl    %ecx, efi32_config(%esi)        /* Handle */
 189        movl    %edx, efi32_config+8(%esi)      /* EFI System table pointer */
 190
 191        /* Relocate efi_config->call() */
 192        leal    efi32_config(%esi), %eax
 193        add     %esi, 40(%eax)
 194        pushl   %eax
 1952:
 196        call    efi_main
 197        cmpl    $0, %eax
 198        movl    %eax, %esi
 199        jne     2f
 200fail:
 201        /* EFI init failed, so hang. */
 202        hlt
 203        jmp     fail
 2042:
 205        movl    BP_code32_start(%esi), %eax
 206        leal    startup_32(%eax), %eax
 207        jmp     *%eax
 208ENDPROC(efi32_stub_entry)
 209#endif
 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 5,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