1b2441318SGreg Kroah-Hartman/* SPDX-License-Identifier: GPL-2.0 */ 20530bf37SThomas Gleixner/* 30530bf37SThomas Gleixner * linux/boot/head.S 40530bf37SThomas Gleixner * 50530bf37SThomas Gleixner * Copyright (C) 1991, 1992, 1993 Linus Torvalds 60530bf37SThomas Gleixner */ 70530bf37SThomas Gleixner 80530bf37SThomas Gleixner/* 90530bf37SThomas Gleixner * head.S contains the 32-bit startup code. 100530bf37SThomas Gleixner * 110530bf37SThomas Gleixner * NOTE!!! Startup happens at absolute address 0x00001000, which is also where 120530bf37SThomas Gleixner * the page directory will exist. The startup code will be overwritten by 130530bf37SThomas Gleixner * the page directory. [According to comments etc elsewhere on a compressed 140530bf37SThomas Gleixner * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC] 150530bf37SThomas Gleixner * 160530bf37SThomas Gleixner * Page 0 is deliberately kept safe, since System Management Mode code in 170530bf37SThomas Gleixner * laptops may need to access the BIOS data stored there. This is also 180530bf37SThomas Gleixner * useful for future device drivers that either access the BIOS via VM86 190530bf37SThomas Gleixner * mode. 200530bf37SThomas Gleixner */ 210530bf37SThomas Gleixner 220530bf37SThomas Gleixner/* 230530bf37SThomas Gleixner * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 240530bf37SThomas Gleixner */ 250530bf37SThomas Gleixner .text 260530bf37SThomas Gleixner 271dc818c1STim Abbott#include <linux/init.h> 280530bf37SThomas Gleixner#include <linux/linkage.h> 290530bf37SThomas Gleixner#include <asm/segment.h> 300341c14dSJeremy Fitzhardinge#include <asm/page_types.h> 310530bf37SThomas Gleixner#include <asm/boot.h> 32a24e7851SRusty Russell#include <asm/asm-offsets.h> 33fb148d83SAlexander Kuleshov#include <asm/bootparam.h> 340530bf37SThomas Gleixner 356d92bc9dSH.J. Lu/* 36a2c4fc4dSArvind Sankar * These symbols needed to be marked as .hidden to prevent the BFD linker from 37a2c4fc4dSArvind Sankar * generating R_386_32 (rather than R_386_RELATIVE) relocations for them when 38a2c4fc4dSArvind Sankar * the 32-bit compressed kernel is linked as PIE. This is no longer necessary, 39a2c4fc4dSArvind Sankar * but it doesn't hurt to keep them .hidden. 406d92bc9dSH.J. Lu */ 416d92bc9dSH.J. Lu .hidden _bss 426d92bc9dSH.J. Lu .hidden _ebss 435214028dSArvind Sankar .hidden _end 446d92bc9dSH.J. Lu 451dc818c1STim Abbott __HEAD 466d685e53SJiri SlabySYM_FUNC_START(startup_32) 47bd53147dSEric W. Biederman cld 48bd53147dSEric W. Biederman cli 49a24e7851SRusty Russell 505f64ec64SH. Peter Anvin/* 515f64ec64SH. Peter Anvin * Calculate the delta between where we were compiled to run 520530bf37SThomas Gleixner * at and where we were actually loaded at. This can only be done 530530bf37SThomas Gleixner * with a short local call on x86. Nothing else will tell us what 540530bf37SThomas Gleixner * address we are running at. The reserved chunk of the real-mode 550530bf37SThomas Gleixner * data at 0x1e4 (defined as a scratch field) are used as the stack 560530bf37SThomas Gleixner * for this calculation. Only 4 bytes are needed. 570530bf37SThomas Gleixner */ 58bd2a3698SH. Peter Anvin leal (BP_scratch+4)(%esi), %esp 590530bf37SThomas Gleixner call 1f 608ef44be3SArvind Sankar1: popl %edx 61a2c4fc4dSArvind Sankar addl $_GLOBAL_OFFSET_TABLE_+(.-1b), %edx 620530bf37SThomas Gleixner 63ef5a7b5eSArvind Sankar /* Load new GDT */ 64a2c4fc4dSArvind Sankar leal gdt@GOTOFF(%edx), %eax 65ef5a7b5eSArvind Sankar movl %eax, 2(%eax) 66ef5a7b5eSArvind Sankar lgdt (%eax) 67ef5a7b5eSArvind Sankar 68ef5a7b5eSArvind Sankar /* Load segment registers with our descriptors */ 69ef5a7b5eSArvind Sankar movl $__BOOT_DS, %eax 70ef5a7b5eSArvind Sankar movl %eax, %ds 71ef5a7b5eSArvind Sankar movl %eax, %es 72ef5a7b5eSArvind Sankar movl %eax, %fs 73ef5a7b5eSArvind Sankar movl %eax, %gs 74ef5a7b5eSArvind Sankar movl %eax, %ss 75ef5a7b5eSArvind Sankar 765f64ec64SH. Peter Anvin/* 77a2c4fc4dSArvind Sankar * %edx contains the address we are loaded at by the boot loader (plus the 78a2c4fc4dSArvind Sankar * offset to the GOT). The below code calculates %ebx to be the address where 79a2c4fc4dSArvind Sankar * we should move the kernel image temporarily for safe in-place decompression 80a2c4fc4dSArvind Sankar * (again, plus the offset to the GOT). 81a2c4fc4dSArvind Sankar * 82a2c4fc4dSArvind Sankar * %ebp is calculated to be the address that the kernel will be decompressed to. 830530bf37SThomas Gleixner */ 840530bf37SThomas Gleixner 850530bf37SThomas Gleixner#ifdef CONFIG_RELOCATABLE 86a2c4fc4dSArvind Sankar leal startup_32@GOTOFF(%edx), %ebx 8737ba7ab5SH. Peter Anvin movl BP_kernel_alignment(%esi), %eax 8837ba7ab5SH. Peter Anvin decl %eax 8937ba7ab5SH. Peter Anvin addl %eax, %ebx 9037ba7ab5SH. Peter Anvin notl %eax 9137ba7ab5SH. Peter Anvin andl %eax, %ebx 928ab3820fSKees Cook cmpl $LOAD_PHYSICAL_ADDR, %ebx 9381a34892SArvind Sankar jae 1f 940530bf37SThomas Gleixner#endif 958ab3820fSKees Cook movl $LOAD_PHYSICAL_ADDR, %ebx 968ab3820fSKees Cook1: 970530bf37SThomas Gleixner 988ef44be3SArvind Sankar movl %ebx, %ebp // Save the output address for later 9902a884c0SH. Peter Anvin /* Target address to relocate to for decompression */ 1008ef44be3SArvind Sankar addl BP_init_size(%esi), %ebx 101a2c4fc4dSArvind Sankar subl $_end@GOTOFF, %ebx 1020530bf37SThomas Gleixner 1030a137736SH. Peter Anvin /* Set up the stack */ 104a2c4fc4dSArvind Sankar leal boot_stack_end@GOTOFF(%ebx), %esp 1050a137736SH. Peter Anvin 10697541912SH. Peter Anvin /* Zero EFLAGS */ 10797541912SH. Peter Anvin pushl $0 10897541912SH. Peter Anvin popfl 10997541912SH. Peter Anvin 1105f64ec64SH. Peter Anvin/* 1115f64ec64SH. Peter Anvin * Copy the compressed kernel to the end of our buffer 1120530bf37SThomas Gleixner * where decompression in place becomes safe. 1130530bf37SThomas Gleixner */ 1140530bf37SThomas Gleixner pushl %esi 115a2c4fc4dSArvind Sankar leal (_bss@GOTOFF-4)(%edx), %esi 116a2c4fc4dSArvind Sankar leal (_bss@GOTOFF-4)(%ebx), %edi 1175b11f1ceSH. Peter Anvin movl $(_bss - startup_32), %ecx 11836d3793cSH. Peter Anvin shrl $2, %ecx 1190530bf37SThomas Gleixner std 12036d3793cSH. Peter Anvin rep movsl 1210530bf37SThomas Gleixner cld 1220530bf37SThomas Gleixner popl %esi 1230530bf37SThomas Gleixner 1245f64ec64SH. Peter Anvin /* 125ef5a7b5eSArvind Sankar * The GDT may get overwritten either during the copy we just did or 126ef5a7b5eSArvind Sankar * during extract_kernel below. To avoid any issues, repoint the GDTR 127c98a76eaSArvind Sankar * to the new copy of the GDT. 128ef5a7b5eSArvind Sankar */ 129a2c4fc4dSArvind Sankar leal gdt@GOTOFF(%ebx), %eax 130c98a76eaSArvind Sankar movl %eax, 2(%eax) 131c98a76eaSArvind Sankar lgdt (%eax) 132ef5a7b5eSArvind Sankar 133ef5a7b5eSArvind Sankar/* 1340530bf37SThomas Gleixner * Jump to the relocated address. 1350530bf37SThomas Gleixner */ 136a2c4fc4dSArvind Sankar leal .Lrelocated@GOTOFF(%ebx), %eax 1370530bf37SThomas Gleixner jmp *%eax 1386d685e53SJiri SlabySYM_FUNC_END(startup_32) 139cb425afdSCyrill Gorcunov 1405f64ec64SH. Peter Anvin .text 141deff8a24SJiri SlabySYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated) 1420530bf37SThomas Gleixner 1430530bf37SThomas Gleixner/* 1440a137736SH. Peter Anvin * Clear BSS (stack is currently empty) 1450530bf37SThomas Gleixner */ 1460530bf37SThomas Gleixner xorl %eax, %eax 147a2c4fc4dSArvind Sankar leal _bss@GOTOFF(%ebx), %edi 148a2c4fc4dSArvind Sankar leal _ebss@GOTOFF(%ebx), %ecx 1490530bf37SThomas Gleixner subl %edi, %ecx 15036d3793cSH. Peter Anvin shrl $2, %ecx 15136d3793cSH. Peter Anvin rep stosl 1520530bf37SThomas Gleixner 153f3670394SLinus Torvalds/* 154c0402881SKees Cook * Do the extraction, and jump to the new kernel.. 1550530bf37SThomas Gleixner */ 156c0402881SKees Cook /* push arguments for extract_kernel: */ 157974f221cSYinghai Lu 1588ef44be3SArvind Sankar pushl %ebp /* output address */ 1595f64ec64SH. Peter Anvin pushl %esi /* real mode pointer */ 160*7734a0f3SAlexander Lobakin call extract_kernel /* returns kernel entry point in %eax */ 1614d2d5424SYinghai Lu addl $24, %esp 1620530bf37SThomas Gleixner 1630530bf37SThomas Gleixner/* 164c0402881SKees Cook * Jump to the extracted kernel. 1650530bf37SThomas Gleixner */ 1660530bf37SThomas Gleixner xorl %ebx, %ebx 1678ab3820fSKees Cook jmp *%eax 168deff8a24SJiri SlabySYM_FUNC_END(.Lrelocated) 1690530bf37SThomas Gleixner 170ef5a7b5eSArvind Sankar .data 171ef5a7b5eSArvind Sankar .balign 8 172ef5a7b5eSArvind SankarSYM_DATA_START_LOCAL(gdt) 173ef5a7b5eSArvind Sankar .word gdt_end - gdt - 1 174ef5a7b5eSArvind Sankar .long 0 175ef5a7b5eSArvind Sankar .word 0 176ef5a7b5eSArvind Sankar .quad 0x0000000000000000 /* Reserved */ 177ef5a7b5eSArvind Sankar .quad 0x00cf9a000000ffff /* __KERNEL_CS */ 178ef5a7b5eSArvind Sankar .quad 0x00cf92000000ffff /* __KERNEL_DS */ 179ef5a7b5eSArvind SankarSYM_DATA_END_LABEL(gdt, SYM_L_LOCAL, gdt_end) 180ef5a7b5eSArvind Sankar 1815f64ec64SH. Peter Anvin/* 1825f64ec64SH. Peter Anvin * Stack and heap for uncompression 1835f64ec64SH. Peter Anvin */ 1840530bf37SThomas Gleixner .bss 1850530bf37SThomas Gleixner .balign 4 1867c539764SAlexander van Heukelumboot_stack: 1877c539764SAlexander van Heukelum .fill BOOT_STACK_SIZE, 1, 0 1887c539764SAlexander van Heukelumboot_stack_end: 189