1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0 */ 2*4882a593Smuzhiyun/* 3*4882a593Smuzhiyun * linux/boot/head.S 4*4882a593Smuzhiyun * 5*4882a593Smuzhiyun * Copyright (C) 1991, 1992, 1993 Linus Torvalds 6*4882a593Smuzhiyun */ 7*4882a593Smuzhiyun 8*4882a593Smuzhiyun/* 9*4882a593Smuzhiyun * head.S contains the 32-bit startup code. 10*4882a593Smuzhiyun * 11*4882a593Smuzhiyun * NOTE!!! Startup happens at absolute address 0x00001000, which is also where 12*4882a593Smuzhiyun * the page directory will exist. The startup code will be overwritten by 13*4882a593Smuzhiyun * the page directory. [According to comments etc elsewhere on a compressed 14*4882a593Smuzhiyun * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC] 15*4882a593Smuzhiyun * 16*4882a593Smuzhiyun * Page 0 is deliberately kept safe, since System Management Mode code in 17*4882a593Smuzhiyun * laptops may need to access the BIOS data stored there. This is also 18*4882a593Smuzhiyun * useful for future device drivers that either access the BIOS via VM86 19*4882a593Smuzhiyun * mode. 20*4882a593Smuzhiyun */ 21*4882a593Smuzhiyun 22*4882a593Smuzhiyun/* 23*4882a593Smuzhiyun * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 24*4882a593Smuzhiyun */ 25*4882a593Smuzhiyun .text 26*4882a593Smuzhiyun 27*4882a593Smuzhiyun#include <linux/init.h> 28*4882a593Smuzhiyun#include <linux/linkage.h> 29*4882a593Smuzhiyun#include <asm/segment.h> 30*4882a593Smuzhiyun#include <asm/page_types.h> 31*4882a593Smuzhiyun#include <asm/boot.h> 32*4882a593Smuzhiyun#include <asm/asm-offsets.h> 33*4882a593Smuzhiyun#include <asm/bootparam.h> 34*4882a593Smuzhiyun 35*4882a593Smuzhiyun/* 36*4882a593Smuzhiyun * These symbols needed to be marked as .hidden to prevent the BFD linker from 37*4882a593Smuzhiyun * generating R_386_32 (rather than R_386_RELATIVE) relocations for them when 38*4882a593Smuzhiyun * the 32-bit compressed kernel is linked as PIE. This is no longer necessary, 39*4882a593Smuzhiyun * but it doesn't hurt to keep them .hidden. 40*4882a593Smuzhiyun */ 41*4882a593Smuzhiyun .hidden _bss 42*4882a593Smuzhiyun .hidden _ebss 43*4882a593Smuzhiyun .hidden _end 44*4882a593Smuzhiyun 45*4882a593Smuzhiyun __HEAD 46*4882a593SmuzhiyunSYM_FUNC_START(startup_32) 47*4882a593Smuzhiyun cld 48*4882a593Smuzhiyun cli 49*4882a593Smuzhiyun 50*4882a593Smuzhiyun/* 51*4882a593Smuzhiyun * Calculate the delta between where we were compiled to run 52*4882a593Smuzhiyun * at and where we were actually loaded at. This can only be done 53*4882a593Smuzhiyun * with a short local call on x86. Nothing else will tell us what 54*4882a593Smuzhiyun * address we are running at. The reserved chunk of the real-mode 55*4882a593Smuzhiyun * data at 0x1e4 (defined as a scratch field) are used as the stack 56*4882a593Smuzhiyun * for this calculation. Only 4 bytes are needed. 57*4882a593Smuzhiyun */ 58*4882a593Smuzhiyun leal (BP_scratch+4)(%esi), %esp 59*4882a593Smuzhiyun call 1f 60*4882a593Smuzhiyun1: popl %edx 61*4882a593Smuzhiyun addl $_GLOBAL_OFFSET_TABLE_+(.-1b), %edx 62*4882a593Smuzhiyun 63*4882a593Smuzhiyun /* Load new GDT */ 64*4882a593Smuzhiyun leal gdt@GOTOFF(%edx), %eax 65*4882a593Smuzhiyun movl %eax, 2(%eax) 66*4882a593Smuzhiyun lgdt (%eax) 67*4882a593Smuzhiyun 68*4882a593Smuzhiyun /* Load segment registers with our descriptors */ 69*4882a593Smuzhiyun movl $__BOOT_DS, %eax 70*4882a593Smuzhiyun movl %eax, %ds 71*4882a593Smuzhiyun movl %eax, %es 72*4882a593Smuzhiyun movl %eax, %fs 73*4882a593Smuzhiyun movl %eax, %gs 74*4882a593Smuzhiyun movl %eax, %ss 75*4882a593Smuzhiyun 76*4882a593Smuzhiyun/* 77*4882a593Smuzhiyun * %edx contains the address we are loaded at by the boot loader (plus the 78*4882a593Smuzhiyun * offset to the GOT). The below code calculates %ebx to be the address where 79*4882a593Smuzhiyun * we should move the kernel image temporarily for safe in-place decompression 80*4882a593Smuzhiyun * (again, plus the offset to the GOT). 81*4882a593Smuzhiyun * 82*4882a593Smuzhiyun * %ebp is calculated to be the address that the kernel will be decompressed to. 83*4882a593Smuzhiyun */ 84*4882a593Smuzhiyun 85*4882a593Smuzhiyun#ifdef CONFIG_RELOCATABLE 86*4882a593Smuzhiyun leal startup_32@GOTOFF(%edx), %ebx 87*4882a593Smuzhiyun 88*4882a593Smuzhiyun#ifdef CONFIG_EFI_STUB 89*4882a593Smuzhiyun/* 90*4882a593Smuzhiyun * If we were loaded via the EFI LoadImage service, startup_32() will be at an 91*4882a593Smuzhiyun * offset to the start of the space allocated for the image. efi_pe_entry() will 92*4882a593Smuzhiyun * set up image_offset to tell us where the image actually starts, so that we 93*4882a593Smuzhiyun * can use the full available buffer. 94*4882a593Smuzhiyun * image_offset = startup_32 - image_base 95*4882a593Smuzhiyun * Otherwise image_offset will be zero and has no effect on the calculations. 96*4882a593Smuzhiyun */ 97*4882a593Smuzhiyun subl image_offset@GOTOFF(%edx), %ebx 98*4882a593Smuzhiyun#endif 99*4882a593Smuzhiyun 100*4882a593Smuzhiyun movl BP_kernel_alignment(%esi), %eax 101*4882a593Smuzhiyun decl %eax 102*4882a593Smuzhiyun addl %eax, %ebx 103*4882a593Smuzhiyun notl %eax 104*4882a593Smuzhiyun andl %eax, %ebx 105*4882a593Smuzhiyun cmpl $LOAD_PHYSICAL_ADDR, %ebx 106*4882a593Smuzhiyun jae 1f 107*4882a593Smuzhiyun#endif 108*4882a593Smuzhiyun movl $LOAD_PHYSICAL_ADDR, %ebx 109*4882a593Smuzhiyun1: 110*4882a593Smuzhiyun 111*4882a593Smuzhiyun movl %ebx, %ebp // Save the output address for later 112*4882a593Smuzhiyun /* Target address to relocate to for decompression */ 113*4882a593Smuzhiyun addl BP_init_size(%esi), %ebx 114*4882a593Smuzhiyun subl $_end@GOTOFF, %ebx 115*4882a593Smuzhiyun 116*4882a593Smuzhiyun /* Set up the stack */ 117*4882a593Smuzhiyun leal boot_stack_end@GOTOFF(%ebx), %esp 118*4882a593Smuzhiyun 119*4882a593Smuzhiyun /* Zero EFLAGS */ 120*4882a593Smuzhiyun pushl $0 121*4882a593Smuzhiyun popfl 122*4882a593Smuzhiyun 123*4882a593Smuzhiyun/* 124*4882a593Smuzhiyun * Copy the compressed kernel to the end of our buffer 125*4882a593Smuzhiyun * where decompression in place becomes safe. 126*4882a593Smuzhiyun */ 127*4882a593Smuzhiyun pushl %esi 128*4882a593Smuzhiyun leal (_bss@GOTOFF-4)(%edx), %esi 129*4882a593Smuzhiyun leal (_bss@GOTOFF-4)(%ebx), %edi 130*4882a593Smuzhiyun movl $(_bss - startup_32), %ecx 131*4882a593Smuzhiyun shrl $2, %ecx 132*4882a593Smuzhiyun std 133*4882a593Smuzhiyun rep movsl 134*4882a593Smuzhiyun cld 135*4882a593Smuzhiyun popl %esi 136*4882a593Smuzhiyun 137*4882a593Smuzhiyun /* 138*4882a593Smuzhiyun * The GDT may get overwritten either during the copy we just did or 139*4882a593Smuzhiyun * during extract_kernel below. To avoid any issues, repoint the GDTR 140*4882a593Smuzhiyun * to the new copy of the GDT. 141*4882a593Smuzhiyun */ 142*4882a593Smuzhiyun leal gdt@GOTOFF(%ebx), %eax 143*4882a593Smuzhiyun movl %eax, 2(%eax) 144*4882a593Smuzhiyun lgdt (%eax) 145*4882a593Smuzhiyun 146*4882a593Smuzhiyun/* 147*4882a593Smuzhiyun * Jump to the relocated address. 148*4882a593Smuzhiyun */ 149*4882a593Smuzhiyun leal .Lrelocated@GOTOFF(%ebx), %eax 150*4882a593Smuzhiyun jmp *%eax 151*4882a593SmuzhiyunSYM_FUNC_END(startup_32) 152*4882a593Smuzhiyun 153*4882a593Smuzhiyun#ifdef CONFIG_EFI_STUB 154*4882a593SmuzhiyunSYM_FUNC_START(efi32_stub_entry) 155*4882a593SmuzhiyunSYM_FUNC_START_ALIAS(efi_stub_entry) 156*4882a593Smuzhiyun add $0x4, %esp 157*4882a593Smuzhiyun movl 8(%esp), %esi /* save boot_params pointer */ 158*4882a593Smuzhiyun call efi_main 159*4882a593Smuzhiyun /* efi_main returns the possibly relocated address of startup_32 */ 160*4882a593Smuzhiyun jmp *%eax 161*4882a593SmuzhiyunSYM_FUNC_END(efi32_stub_entry) 162*4882a593SmuzhiyunSYM_FUNC_END_ALIAS(efi_stub_entry) 163*4882a593Smuzhiyun#endif 164*4882a593Smuzhiyun 165*4882a593Smuzhiyun .text 166*4882a593SmuzhiyunSYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated) 167*4882a593Smuzhiyun 168*4882a593Smuzhiyun/* 169*4882a593Smuzhiyun * Clear BSS (stack is currently empty) 170*4882a593Smuzhiyun */ 171*4882a593Smuzhiyun xorl %eax, %eax 172*4882a593Smuzhiyun leal _bss@GOTOFF(%ebx), %edi 173*4882a593Smuzhiyun leal _ebss@GOTOFF(%ebx), %ecx 174*4882a593Smuzhiyun subl %edi, %ecx 175*4882a593Smuzhiyun shrl $2, %ecx 176*4882a593Smuzhiyun rep stosl 177*4882a593Smuzhiyun 178*4882a593Smuzhiyun/* 179*4882a593Smuzhiyun * Do the extraction, and jump to the new kernel.. 180*4882a593Smuzhiyun */ 181*4882a593Smuzhiyun /* push arguments for extract_kernel: */ 182*4882a593Smuzhiyun 183*4882a593Smuzhiyun pushl output_len@GOTOFF(%ebx) /* decompressed length, end of relocs */ 184*4882a593Smuzhiyun pushl %ebp /* output address */ 185*4882a593Smuzhiyun pushl input_len@GOTOFF(%ebx) /* input_len */ 186*4882a593Smuzhiyun leal input_data@GOTOFF(%ebx), %eax 187*4882a593Smuzhiyun pushl %eax /* input_data */ 188*4882a593Smuzhiyun leal boot_heap@GOTOFF(%ebx), %eax 189*4882a593Smuzhiyun pushl %eax /* heap area */ 190*4882a593Smuzhiyun pushl %esi /* real mode pointer */ 191*4882a593Smuzhiyun call extract_kernel /* returns kernel location in %eax */ 192*4882a593Smuzhiyun addl $24, %esp 193*4882a593Smuzhiyun 194*4882a593Smuzhiyun/* 195*4882a593Smuzhiyun * Jump to the extracted kernel. 196*4882a593Smuzhiyun */ 197*4882a593Smuzhiyun xorl %ebx, %ebx 198*4882a593Smuzhiyun jmp *%eax 199*4882a593SmuzhiyunSYM_FUNC_END(.Lrelocated) 200*4882a593Smuzhiyun 201*4882a593Smuzhiyun .data 202*4882a593Smuzhiyun .balign 8 203*4882a593SmuzhiyunSYM_DATA_START_LOCAL(gdt) 204*4882a593Smuzhiyun .word gdt_end - gdt - 1 205*4882a593Smuzhiyun .long 0 206*4882a593Smuzhiyun .word 0 207*4882a593Smuzhiyun .quad 0x0000000000000000 /* Reserved */ 208*4882a593Smuzhiyun .quad 0x00cf9a000000ffff /* __KERNEL_CS */ 209*4882a593Smuzhiyun .quad 0x00cf92000000ffff /* __KERNEL_DS */ 210*4882a593SmuzhiyunSYM_DATA_END_LABEL(gdt, SYM_L_LOCAL, gdt_end) 211*4882a593Smuzhiyun 212*4882a593Smuzhiyun#ifdef CONFIG_EFI_STUB 213*4882a593SmuzhiyunSYM_DATA(image_offset, .long 0) 214*4882a593Smuzhiyun#endif 215*4882a593Smuzhiyun 216*4882a593Smuzhiyun/* 217*4882a593Smuzhiyun * Stack and heap for uncompression 218*4882a593Smuzhiyun */ 219*4882a593Smuzhiyun .bss 220*4882a593Smuzhiyun .balign 4 221*4882a593Smuzhiyunboot_heap: 222*4882a593Smuzhiyun .fill BOOT_HEAP_SIZE, 1, 0 223*4882a593Smuzhiyunboot_stack: 224*4882a593Smuzhiyun .fill BOOT_STACK_SIZE, 1, 0 225*4882a593Smuzhiyunboot_stack_end: 226