| .. | .. |
|---|
| 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 | /* |
|---|