/* SPDX-License-Identifier: GPL-2.0 */1/*2* linux/boot/head.S3*4* Copyright (C) 1991, 1992, 1993 Linus Torvalds5*/67/*8* head.S contains the 32-bit startup code.9*10* NOTE!!! Startup happens at absolute address 0x00001000, which is also where11* the page directory will exist. The startup code will be overwritten by12* the page directory. [According to comments etc elsewhere on a compressed13* 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 in16* laptops may need to access the BIOS data stored there. This is also17* useful for future device drivers that either access the BIOS via VM8618* mode.19*/2021/*22* High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 199623*/24.text2526#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>3334/*35* These symbols needed to be marked as .hidden to prevent the BFD linker from36* generating R_386_32 (rather than R_386_RELATIVE) relocations for them when37* the 32-bit compressed kernel is linked as PIE. This is no longer necessary,38* but it doesn't hurt to keep them .hidden.39*/40.hidden _bss41.hidden _ebss42.hidden _end4344__HEAD45SYM_FUNC_START(startup_32)46cld47cli4849/*50* Calculate the delta between where we were compiled to run51* at and where we were actually loaded at. This can only be done52* with a short local call on x86. Nothing else will tell us what53* address we are running at. The reserved chunk of the real-mode54* data at 0x1e4 (defined as a scratch field) are used as the stack55* for this calculation. Only 4 bytes are needed.56*/57leal (BP_scratch+4)(%esi), %esp58call 1f591: popl %edx60addl $_GLOBAL_OFFSET_TABLE_+(.-1b), %edx6162/* Load new GDT */63leal gdt@GOTOFF(%edx), %eax64movl %eax, 2(%eax)65lgdt (%eax)6667/* Load segment registers with our descriptors */68movl $__BOOT_DS, %eax69movl %eax, %ds70movl %eax, %es71movl %eax, %fs72movl %eax, %gs73movl %eax, %ss7475/*76* %edx contains the address we are loaded at by the boot loader (plus the77* offset to the GOT). The below code calculates %ebx to be the address where78* we should move the kernel image temporarily for safe in-place decompression79* (again, plus the offset to the GOT).80*81* %ebp is calculated to be the address that the kernel will be decompressed to.82*/8384#ifdef CONFIG_RELOCATABLE85leal startup_32@GOTOFF(%edx), %ebx86movl BP_kernel_alignment(%esi), %eax87decl %eax88addl %eax, %ebx89notl %eax90andl %eax, %ebx91cmpl $LOAD_PHYSICAL_ADDR, %ebx92jae 1f93#endif94movl $LOAD_PHYSICAL_ADDR, %ebx951:9697movl %ebx, %ebp // Save the output address for later98/* Target address to relocate to for decompression */99addl BP_init_size(%esi), %ebx100subl $_end@GOTOFF, %ebx101102/* Set up the stack */103leal boot_stack_end@GOTOFF(%ebx), %esp104105/* Zero EFLAGS */106pushl $0107popfl108109/*110* Copy the compressed kernel to the end of our buffer111* where decompression in place becomes safe.112*/113pushl %esi114leal (_bss@GOTOFF-4)(%edx), %esi115leal (_bss@GOTOFF-4)(%ebx), %edi116movl $(_bss - startup_32), %ecx117shrl $2, %ecx118std119rep movsl120cld121popl %esi122123/*124* The GDT may get overwritten either during the copy we just did or125* during extract_kernel below. To avoid any issues, repoint the GDTR126* to the new copy of the GDT.127*/128leal gdt@GOTOFF(%ebx), %eax129movl %eax, 2(%eax)130lgdt (%eax)131132/*133* Jump to the relocated address.134*/135leal .Lrelocated@GOTOFF(%ebx), %eax136jmp *%eax137SYM_FUNC_END(startup_32)138139.text140SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)141142/*143* Clear BSS (stack is currently empty)144*/145xorl %eax, %eax146leal _bss@GOTOFF(%ebx), %edi147leal _ebss@GOTOFF(%ebx), %ecx148subl %edi, %ecx149shrl $2, %ecx150rep stosl151152/*153* Do the extraction, and jump to the new kernel..154*/155/* push arguments for extract_kernel: */156157pushl %ebp /* output address */158pushl %esi /* real mode pointer */159call extract_kernel /* returns kernel entry point in %eax */160addl $24, %esp161162/*163* Jump to the extracted kernel.164*/165xorl %ebx, %ebx166jmp *%eax167SYM_FUNC_END(.Lrelocated)168169.data170.balign 8171SYM_DATA_START_LOCAL(gdt)172.word gdt_end - gdt - 1173.long 0174.word 0175.quad 0x0000000000000000 /* Reserved */176.quad 0x00cf9a000000ffff /* __KERNEL_CS */177.quad 0x00cf92000000ffff /* __KERNEL_DS */178SYM_DATA_END_LABEL(gdt, SYM_L_LOCAL, gdt_end)179180/*181* Stack and heap for uncompression182*/183.bss184.balign 4185boot_stack:186.fill BOOT_STACK_SIZE, 1, 0187boot_stack_end:188189190