Linux 6.10-rc3
[sfrench/cifs-2.6.git] / arch / x86 / boot / compressed / head_32.S
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  * These symbols needed to be marked as .hidden to prevent the BFD linker from
37  * generating R_386_32 (rather than R_386_RELATIVE) relocations for them when
38  * the 32-bit compressed kernel is linked as PIE. This is no longer necessary,
39  * but it doesn't hurt to keep them .hidden.
40  */
41         .hidden _bss
42         .hidden _ebss
43         .hidden _end
44
45         __HEAD
46 SYM_FUNC_START(startup_32)
47         cld
48         cli
49
50 /*
51  * Calculate the delta between where we were compiled to run
52  * at and where we were actually loaded at.  This can only be done
53  * with a short local call on x86.  Nothing  else will tell us what
54  * address we are running at.  The reserved chunk of the real-mode
55  * data at 0x1e4 (defined as a scratch field) are used as the stack
56  * for this calculation. Only 4 bytes are needed.
57  */
58         leal    (BP_scratch+4)(%esi), %esp
59         call    1f
60 1:      popl    %edx
61         addl    $_GLOBAL_OFFSET_TABLE_+(.-1b), %edx
62
63         /* Load new GDT */
64         leal    gdt@GOTOFF(%edx), %eax
65         movl    %eax, 2(%eax)
66         lgdt    (%eax)
67
68         /* Load segment registers with our descriptors */
69         movl    $__BOOT_DS, %eax
70         movl    %eax, %ds
71         movl    %eax, %es
72         movl    %eax, %fs
73         movl    %eax, %gs
74         movl    %eax, %ss
75
76 /*
77  * %edx contains the address we are loaded at by the boot loader (plus the
78  * offset to the GOT).  The below code calculates %ebx to be the address where
79  * we should move the kernel image temporarily for safe in-place decompression
80  * (again, plus the offset to the GOT).
81  *
82  * %ebp is calculated to be the address that the kernel will be decompressed to.
83  */
84
85 #ifdef CONFIG_RELOCATABLE
86         leal    startup_32@GOTOFF(%edx), %ebx
87         movl    BP_kernel_alignment(%esi), %eax
88         decl    %eax
89         addl    %eax, %ebx
90         notl    %eax
91         andl    %eax, %ebx
92         cmpl    $LOAD_PHYSICAL_ADDR, %ebx
93         jae     1f
94 #endif
95         movl    $LOAD_PHYSICAL_ADDR, %ebx
96 1:
97
98         movl    %ebx, %ebp      // Save the output address for later
99         /* Target address to relocate to for decompression */
100         addl    BP_init_size(%esi), %ebx
101         subl    $_end@GOTOFF, %ebx
102
103         /* Set up the stack */
104         leal    boot_stack_end@GOTOFF(%ebx), %esp
105
106         /* Zero EFLAGS */
107         pushl   $0
108         popfl
109
110 /*
111  * Copy the compressed kernel to the end of our buffer
112  * where decompression in place becomes safe.
113  */
114         pushl   %esi
115         leal    (_bss@GOTOFF-4)(%edx), %esi
116         leal    (_bss@GOTOFF-4)(%ebx), %edi
117         movl    $(_bss - startup_32), %ecx
118         shrl    $2, %ecx
119         std
120         rep     movsl
121         cld
122         popl    %esi
123
124         /*
125          * The GDT may get overwritten either during the copy we just did or
126          * during extract_kernel below. To avoid any issues, repoint the GDTR
127          * to the new copy of the GDT.
128          */
129         leal    gdt@GOTOFF(%ebx), %eax
130         movl    %eax, 2(%eax)
131         lgdt    (%eax)
132
133 /*
134  * Jump to the relocated address.
135  */
136         leal    .Lrelocated@GOTOFF(%ebx), %eax
137         jmp     *%eax
138 SYM_FUNC_END(startup_32)
139
140         .text
141 SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
142
143 /*
144  * Clear BSS (stack is currently empty)
145  */
146         xorl    %eax, %eax
147         leal    _bss@GOTOFF(%ebx), %edi
148         leal    _ebss@GOTOFF(%ebx), %ecx
149         subl    %edi, %ecx
150         shrl    $2, %ecx
151         rep     stosl
152
153 /*
154  * Do the extraction, and jump to the new kernel..
155  */
156         /* push arguments for extract_kernel: */
157
158         pushl   %ebp                    /* output address */
159         pushl   %esi                    /* real mode pointer */
160         call    extract_kernel          /* returns kernel entry point in %eax */
161         addl    $24, %esp
162
163 /*
164  * Jump to the extracted kernel.
165  */
166         xorl    %ebx, %ebx
167         jmp     *%eax
168 SYM_FUNC_END(.Lrelocated)
169
170         .data
171         .balign 8
172 SYM_DATA_START_LOCAL(gdt)
173         .word   gdt_end - gdt - 1
174         .long   0
175         .word   0
176         .quad   0x0000000000000000      /* Reserved */
177         .quad   0x00cf9a000000ffff      /* __KERNEL_CS */
178         .quad   0x00cf92000000ffff      /* __KERNEL_DS */
179 SYM_DATA_END_LABEL(gdt, SYM_L_LOCAL, gdt_end)
180
181 /*
182  * Stack and heap for uncompression
183  */
184         .bss
185         .balign 4
186 boot_stack:
187         .fill BOOT_STACK_SIZE, 1, 0
188 boot_stack_end: