.. | .. |
---|
33 | 33 | #include <asm/bootparam.h> |
---|
34 | 34 | |
---|
35 | 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, _egot and _end, 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, _egot and _end as |
---|
56 | | - * hidden: |
---|
| 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. |
---|
57 | 40 | */ |
---|
58 | 41 | .hidden _bss |
---|
59 | 42 | .hidden _ebss |
---|
60 | | - .hidden _got |
---|
61 | | - .hidden _egot |
---|
62 | 43 | .hidden _end |
---|
63 | 44 | |
---|
64 | 45 | __HEAD |
---|
65 | | -ENTRY(startup_32) |
---|
| 46 | +SYM_FUNC_START(startup_32) |
---|
66 | 47 | cld |
---|
67 | | - /* |
---|
68 | | - * Test KEEP_SEGMENTS flag to see if the bootloader is asking |
---|
69 | | - * us to not reload segments |
---|
70 | | - */ |
---|
71 | | - testb $KEEP_SEGMENTS, BP_loadflags(%esi) |
---|
72 | | - jnz 1f |
---|
73 | | - |
---|
74 | 48 | cli |
---|
75 | | - movl $__BOOT_DS, %eax |
---|
76 | | - movl %eax, %ds |
---|
77 | | - movl %eax, %es |
---|
78 | | - movl %eax, %fs |
---|
79 | | - movl %eax, %gs |
---|
80 | | - movl %eax, %ss |
---|
81 | | -1: |
---|
82 | 49 | |
---|
83 | 50 | /* |
---|
84 | 51 | * Calculate the delta between where we were compiled to run |
---|
.. | .. |
---|
90 | 57 | */ |
---|
91 | 58 | leal (BP_scratch+4)(%esi), %esp |
---|
92 | 59 | call 1f |
---|
93 | | -1: popl %ebp |
---|
94 | | - subl $1b, %ebp |
---|
| 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 |
---|
95 | 75 | |
---|
96 | 76 | /* |
---|
97 | | - * %ebp contains the address we are loaded at by the boot loader and %ebx |
---|
98 | | - * contains the address where we should move the kernel image temporarily |
---|
99 | | - * for safe in-place decompression. |
---|
| 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. |
---|
100 | 83 | */ |
---|
101 | 84 | |
---|
102 | 85 | #ifdef CONFIG_RELOCATABLE |
---|
103 | | - movl %ebp, %ebx |
---|
| 86 | + leal startup_32@GOTOFF(%edx), %ebx |
---|
| 87 | + |
---|
| 88 | +#ifdef CONFIG_EFI_STUB |
---|
| 89 | +/* |
---|
| 90 | + * If we were loaded via the EFI LoadImage service, startup_32() will be at an |
---|
| 91 | + * offset to the start of the space allocated for the image. efi_pe_entry() will |
---|
| 92 | + * set up image_offset to tell us where the image actually starts, so that we |
---|
| 93 | + * can use the full available buffer. |
---|
| 94 | + * image_offset = startup_32 - image_base |
---|
| 95 | + * Otherwise image_offset will be zero and has no effect on the calculations. |
---|
| 96 | + */ |
---|
| 97 | + subl image_offset@GOTOFF(%edx), %ebx |
---|
| 98 | +#endif |
---|
| 99 | + |
---|
104 | 100 | movl BP_kernel_alignment(%esi), %eax |
---|
105 | 101 | decl %eax |
---|
106 | 102 | addl %eax, %ebx |
---|
.. | .. |
---|
112 | 108 | movl $LOAD_PHYSICAL_ADDR, %ebx |
---|
113 | 109 | 1: |
---|
114 | 110 | |
---|
| 111 | + movl %ebx, %ebp // Save the output address for later |
---|
115 | 112 | /* Target address to relocate to for decompression */ |
---|
116 | | - movl BP_init_size(%esi), %eax |
---|
117 | | - subl $_end, %eax |
---|
118 | | - addl %eax, %ebx |
---|
| 113 | + addl BP_init_size(%esi), %ebx |
---|
| 114 | + subl $_end@GOTOFF, %ebx |
---|
119 | 115 | |
---|
120 | 116 | /* Set up the stack */ |
---|
121 | | - leal boot_stack_end(%ebx), %esp |
---|
| 117 | + leal boot_stack_end@GOTOFF(%ebx), %esp |
---|
122 | 118 | |
---|
123 | 119 | /* Zero EFLAGS */ |
---|
124 | 120 | pushl $0 |
---|
.. | .. |
---|
129 | 125 | * where decompression in place becomes safe. |
---|
130 | 126 | */ |
---|
131 | 127 | pushl %esi |
---|
132 | | - leal (_bss-4)(%ebp), %esi |
---|
133 | | - leal (_bss-4)(%ebx), %edi |
---|
| 128 | + leal (_bss@GOTOFF-4)(%edx), %esi |
---|
| 129 | + leal (_bss@GOTOFF-4)(%ebx), %edi |
---|
134 | 130 | movl $(_bss - startup_32), %ecx |
---|
135 | 131 | shrl $2, %ecx |
---|
136 | 132 | std |
---|
.. | .. |
---|
138 | 134 | cld |
---|
139 | 135 | popl %esi |
---|
140 | 136 | |
---|
| 137 | + /* |
---|
| 138 | + * The GDT may get overwritten either during the copy we just did or |
---|
| 139 | + * during extract_kernel below. To avoid any issues, repoint the GDTR |
---|
| 140 | + * to the new copy of the GDT. |
---|
| 141 | + */ |
---|
| 142 | + leal gdt@GOTOFF(%ebx), %eax |
---|
| 143 | + movl %eax, 2(%eax) |
---|
| 144 | + lgdt (%eax) |
---|
| 145 | + |
---|
141 | 146 | /* |
---|
142 | 147 | * Jump to the relocated address. |
---|
143 | 148 | */ |
---|
144 | | - leal relocated(%ebx), %eax |
---|
| 149 | + leal .Lrelocated@GOTOFF(%ebx), %eax |
---|
145 | 150 | jmp *%eax |
---|
146 | | -ENDPROC(startup_32) |
---|
| 151 | +SYM_FUNC_END(startup_32) |
---|
147 | 152 | |
---|
148 | 153 | #ifdef CONFIG_EFI_STUB |
---|
149 | | -/* |
---|
150 | | - * We don't need the return address, so set up the stack so efi_main() can find |
---|
151 | | - * its arguments. |
---|
152 | | - */ |
---|
153 | | -ENTRY(efi_pe_entry) |
---|
| 154 | +SYM_FUNC_START(efi32_stub_entry) |
---|
| 155 | +SYM_FUNC_START_ALIAS(efi_stub_entry) |
---|
154 | 156 | add $0x4, %esp |
---|
155 | | - |
---|
156 | | - call 1f |
---|
157 | | -1: popl %esi |
---|
158 | | - subl $1b, %esi |
---|
159 | | - |
---|
160 | | - popl %ecx |
---|
161 | | - movl %ecx, efi32_config(%esi) /* Handle */ |
---|
162 | | - popl %ecx |
---|
163 | | - movl %ecx, efi32_config+8(%esi) /* EFI System table pointer */ |
---|
164 | | - |
---|
165 | | - /* Relocate efi_config->call() */ |
---|
166 | | - leal efi32_config(%esi), %eax |
---|
167 | | - add %esi, 40(%eax) |
---|
168 | | - pushl %eax |
---|
169 | | - |
---|
170 | | - call make_boot_params |
---|
171 | | - cmpl $0, %eax |
---|
172 | | - je fail |
---|
173 | | - movl %esi, BP_code32_start(%eax) |
---|
174 | | - popl %ecx |
---|
175 | | - pushl %eax |
---|
176 | | - pushl %ecx |
---|
177 | | - jmp 2f /* Skip efi_config initialization */ |
---|
178 | | -ENDPROC(efi_pe_entry) |
---|
179 | | - |
---|
180 | | -ENTRY(efi32_stub_entry) |
---|
181 | | - add $0x4, %esp |
---|
182 | | - popl %ecx |
---|
183 | | - popl %edx |
---|
184 | | - |
---|
185 | | - call 1f |
---|
186 | | -1: popl %esi |
---|
187 | | - subl $1b, %esi |
---|
188 | | - |
---|
189 | | - movl %ecx, efi32_config(%esi) /* Handle */ |
---|
190 | | - movl %edx, efi32_config+8(%esi) /* EFI System table pointer */ |
---|
191 | | - |
---|
192 | | - /* Relocate efi_config->call() */ |
---|
193 | | - leal efi32_config(%esi), %eax |
---|
194 | | - add %esi, 40(%eax) |
---|
195 | | - pushl %eax |
---|
196 | | -2: |
---|
| 157 | + movl 8(%esp), %esi /* save boot_params pointer */ |
---|
197 | 158 | call efi_main |
---|
198 | | - cmpl $0, %eax |
---|
199 | | - movl %eax, %esi |
---|
200 | | - jne 2f |
---|
201 | | -fail: |
---|
202 | | - /* EFI init failed, so hang. */ |
---|
203 | | - hlt |
---|
204 | | - jmp fail |
---|
205 | | -2: |
---|
206 | | - movl BP_code32_start(%esi), %eax |
---|
207 | | - leal startup_32(%eax), %eax |
---|
| 159 | + /* efi_main returns the possibly relocated address of startup_32 */ |
---|
208 | 160 | jmp *%eax |
---|
209 | | -ENDPROC(efi32_stub_entry) |
---|
| 161 | +SYM_FUNC_END(efi32_stub_entry) |
---|
| 162 | +SYM_FUNC_END_ALIAS(efi_stub_entry) |
---|
210 | 163 | #endif |
---|
211 | 164 | |
---|
212 | 165 | .text |
---|
213 | | -relocated: |
---|
| 166 | +SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated) |
---|
214 | 167 | |
---|
215 | 168 | /* |
---|
216 | 169 | * Clear BSS (stack is currently empty) |
---|
217 | 170 | */ |
---|
218 | 171 | xorl %eax, %eax |
---|
219 | | - leal _bss(%ebx), %edi |
---|
220 | | - leal _ebss(%ebx), %ecx |
---|
| 172 | + leal _bss@GOTOFF(%ebx), %edi |
---|
| 173 | + leal _ebss@GOTOFF(%ebx), %ecx |
---|
221 | 174 | subl %edi, %ecx |
---|
222 | 175 | shrl $2, %ecx |
---|
223 | 176 | rep stosl |
---|
224 | 177 | |
---|
225 | 178 | /* |
---|
226 | | - * Adjust our own GOT |
---|
227 | | - */ |
---|
228 | | - leal _got(%ebx), %edx |
---|
229 | | - leal _egot(%ebx), %ecx |
---|
230 | | -1: |
---|
231 | | - cmpl %ecx, %edx |
---|
232 | | - jae 2f |
---|
233 | | - addl %ebx, (%edx) |
---|
234 | | - addl $4, %edx |
---|
235 | | - jmp 1b |
---|
236 | | -2: |
---|
237 | | - |
---|
238 | | -/* |
---|
239 | 179 | * Do the extraction, and jump to the new kernel.. |
---|
240 | 180 | */ |
---|
241 | | - /* push arguments for extract_kernel: */ |
---|
242 | | - pushl $z_output_len /* decompressed length, end of relocs */ |
---|
| 181 | + /* push arguments for extract_kernel: */ |
---|
243 | 182 | |
---|
244 | | - movl BP_init_size(%esi), %eax |
---|
245 | | - subl $_end, %eax |
---|
246 | | - movl %ebx, %ebp |
---|
247 | | - subl %eax, %ebp |
---|
248 | | - pushl %ebp /* output address */ |
---|
249 | | - |
---|
250 | | - pushl $z_input_len /* input_len */ |
---|
251 | | - leal input_data(%ebx), %eax |
---|
252 | | - pushl %eax /* input_data */ |
---|
253 | | - leal boot_heap(%ebx), %eax |
---|
254 | | - pushl %eax /* heap area */ |
---|
255 | | - pushl %esi /* real mode pointer */ |
---|
256 | | - call extract_kernel /* returns kernel location in %eax */ |
---|
| 183 | + pushl output_len@GOTOFF(%ebx) /* decompressed length, end of relocs */ |
---|
| 184 | + pushl %ebp /* output address */ |
---|
| 185 | + pushl input_len@GOTOFF(%ebx) /* input_len */ |
---|
| 186 | + leal input_data@GOTOFF(%ebx), %eax |
---|
| 187 | + pushl %eax /* input_data */ |
---|
| 188 | + leal boot_heap@GOTOFF(%ebx), %eax |
---|
| 189 | + pushl %eax /* heap area */ |
---|
| 190 | + pushl %esi /* real mode pointer */ |
---|
| 191 | + call extract_kernel /* returns kernel location in %eax */ |
---|
257 | 192 | addl $24, %esp |
---|
258 | 193 | |
---|
259 | 194 | /* |
---|
.. | .. |
---|
261 | 196 | */ |
---|
262 | 197 | xorl %ebx, %ebx |
---|
263 | 198 | jmp *%eax |
---|
| 199 | +SYM_FUNC_END(.Lrelocated) |
---|
| 200 | + |
---|
| 201 | + .data |
---|
| 202 | + .balign 8 |
---|
| 203 | +SYM_DATA_START_LOCAL(gdt) |
---|
| 204 | + .word gdt_end - gdt - 1 |
---|
| 205 | + .long 0 |
---|
| 206 | + .word 0 |
---|
| 207 | + .quad 0x0000000000000000 /* Reserved */ |
---|
| 208 | + .quad 0x00cf9a000000ffff /* __KERNEL_CS */ |
---|
| 209 | + .quad 0x00cf92000000ffff /* __KERNEL_DS */ |
---|
| 210 | +SYM_DATA_END_LABEL(gdt, SYM_L_LOCAL, gdt_end) |
---|
264 | 211 | |
---|
265 | 212 | #ifdef CONFIG_EFI_STUB |
---|
266 | | - .data |
---|
267 | | -efi32_config: |
---|
268 | | - .fill 5,8,0 |
---|
269 | | - .long efi_call_phys |
---|
270 | | - .long 0 |
---|
271 | | - .byte 0 |
---|
| 213 | +SYM_DATA(image_offset, .long 0) |
---|
272 | 214 | #endif |
---|
273 | 215 | |
---|
274 | 216 | /* |
---|