diff options
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/Kconfig | 8 | ||||
-rw-r--r-- | arch/x86/Makefile | 8 | ||||
-rw-r--r-- | arch/x86/boot/compressed/head_32.S | 31 | ||||
-rw-r--r-- | arch/x86/boot/compressed/head_64.S | 1 | ||||
-rw-r--r-- | arch/x86/boot/compressed/misc.c | 77 | ||||
-rw-r--r-- | arch/x86/include/asm/page_32_types.h | 2 | ||||
-rw-r--r-- | arch/x86/include/asm/page_64_types.h | 5 | ||||
-rw-r--r-- | arch/x86/include/asm/page_types.h | 5 |
8 files changed, 97 insertions, 40 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index b32ebf92b0ce..8002668d60a1 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -1716,9 +1716,10 @@ config X86_NEED_RELOCS | |||
1716 | depends on X86_32 && RELOCATABLE | 1716 | depends on X86_32 && RELOCATABLE |
1717 | 1717 | ||
1718 | config PHYSICAL_ALIGN | 1718 | config PHYSICAL_ALIGN |
1719 | hex "Alignment value to which kernel should be aligned" if X86_32 | 1719 | hex "Alignment value to which kernel should be aligned" |
1720 | default "0x1000000" | 1720 | default "0x1000000" |
1721 | range 0x2000 0x1000000 | 1721 | range 0x2000 0x1000000 if X86_32 |
1722 | range 0x200000 0x1000000 if X86_64 | ||
1722 | ---help--- | 1723 | ---help--- |
1723 | This value puts the alignment restrictions on physical address | 1724 | This value puts the alignment restrictions on physical address |
1724 | where kernel is loaded and run from. Kernel is compiled for an | 1725 | where kernel is loaded and run from. Kernel is compiled for an |
@@ -1736,6 +1737,9 @@ config PHYSICAL_ALIGN | |||
1736 | end result is that kernel runs from a physical address meeting | 1737 | end result is that kernel runs from a physical address meeting |
1737 | above alignment restrictions. | 1738 | above alignment restrictions. |
1738 | 1739 | ||
1740 | On 32-bit this value must be a multiple of 0x2000. On 64-bit | ||
1741 | this value must be a multiple of 0x200000. | ||
1742 | |||
1739 | Don't change this unless you know what you are doing. | 1743 | Don't change this unless you know what you are doing. |
1740 | 1744 | ||
1741 | config HOTPLUG_CPU | 1745 | config HOTPLUG_CPU |
diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 07639c656fcd..41250fb33985 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile | |||
@@ -16,6 +16,10 @@ endif | |||
16 | # e.g.: obj-y += foo_$(BITS).o | 16 | # e.g.: obj-y += foo_$(BITS).o |
17 | export BITS | 17 | export BITS |
18 | 18 | ||
19 | ifdef CONFIG_X86_NEED_RELOCS | ||
20 | LDFLAGS_vmlinux := --emit-relocs | ||
21 | endif | ||
22 | |||
19 | ifeq ($(CONFIG_X86_32),y) | 23 | ifeq ($(CONFIG_X86_32),y) |
20 | BITS := 32 | 24 | BITS := 32 |
21 | UTS_MACHINE := i386 | 25 | UTS_MACHINE := i386 |
@@ -25,10 +29,6 @@ ifeq ($(CONFIG_X86_32),y) | |||
25 | KBUILD_AFLAGS += $(biarch) | 29 | KBUILD_AFLAGS += $(biarch) |
26 | KBUILD_CFLAGS += $(biarch) | 30 | KBUILD_CFLAGS += $(biarch) |
27 | 31 | ||
28 | ifdef CONFIG_RELOCATABLE | ||
29 | LDFLAGS_vmlinux := --emit-relocs | ||
30 | endif | ||
31 | |||
32 | KBUILD_CFLAGS += -msoft-float -mregparm=3 -freg-struct-return | 32 | KBUILD_CFLAGS += -msoft-float -mregparm=3 -freg-struct-return |
33 | 33 | ||
34 | # Never want PIC in a 32-bit kernel, prevent breakage with GCC built | 34 | # Never want PIC in a 32-bit kernel, prevent breakage with GCC built |
diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S index 1e3184f6072f..5d6f6891b188 100644 --- a/arch/x86/boot/compressed/head_32.S +++ b/arch/x86/boot/compressed/head_32.S | |||
@@ -181,8 +181,9 @@ relocated: | |||
181 | /* | 181 | /* |
182 | * Do the decompression, and jump to the new kernel.. | 182 | * Do the decompression, and jump to the new kernel.. |
183 | */ | 183 | */ |
184 | leal z_extract_offset_negative(%ebx), %ebp | ||
185 | /* push arguments for decompress_kernel: */ | 184 | /* push arguments for decompress_kernel: */ |
185 | pushl $z_output_len /* decompressed length */ | ||
186 | leal z_extract_offset_negative(%ebx), %ebp | ||
186 | pushl %ebp /* output address */ | 187 | pushl %ebp /* output address */ |
187 | pushl $z_input_len /* input_len */ | 188 | pushl $z_input_len /* input_len */ |
188 | leal input_data(%ebx), %eax | 189 | leal input_data(%ebx), %eax |
@@ -191,33 +192,7 @@ relocated: | |||
191 | pushl %eax /* heap area */ | 192 | pushl %eax /* heap area */ |
192 | pushl %esi /* real mode pointer */ | 193 | pushl %esi /* real mode pointer */ |
193 | call decompress_kernel | 194 | call decompress_kernel |
194 | addl $20, %esp | 195 | addl $24, %esp |
195 | |||
196 | #if CONFIG_RELOCATABLE | ||
197 | /* | ||
198 | * Find the address of the relocations. | ||
199 | */ | ||
200 | leal z_output_len(%ebp), %edi | ||
201 | |||
202 | /* | ||
203 | * Calculate the delta between where vmlinux was compiled to run | ||
204 | * and where it was actually loaded. | ||
205 | */ | ||
206 | movl %ebp, %ebx | ||
207 | subl $LOAD_PHYSICAL_ADDR, %ebx | ||
208 | jz 2f /* Nothing to be done if loaded at compiled addr. */ | ||
209 | /* | ||
210 | * Process relocations. | ||
211 | */ | ||
212 | |||
213 | 1: subl $4, %edi | ||
214 | movl (%edi), %ecx | ||
215 | testl %ecx, %ecx | ||
216 | jz 2f | ||
217 | addl %ebx, -__PAGE_OFFSET(%ebx, %ecx) | ||
218 | jmp 1b | ||
219 | 2: | ||
220 | #endif | ||
221 | 196 | ||
222 | /* | 197 | /* |
223 | * Jump to the decompressed kernel. | 198 | * Jump to the decompressed kernel. |
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S index 06e71c2c16bf..c337422b575d 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S | |||
@@ -338,6 +338,7 @@ relocated: | |||
338 | leaq input_data(%rip), %rdx /* input_data */ | 338 | leaq input_data(%rip), %rdx /* input_data */ |
339 | movl $z_input_len, %ecx /* input_len */ | 339 | movl $z_input_len, %ecx /* input_len */ |
340 | movq %rbp, %r8 /* output target address */ | 340 | movq %rbp, %r8 /* output target address */ |
341 | movq $z_output_len, %r9 /* decompressed length */ | ||
341 | call decompress_kernel | 342 | call decompress_kernel |
342 | popq %rsi | 343 | popq %rsi |
343 | 344 | ||
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index 0319c88290a5..434f077d2c4d 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c | |||
@@ -271,6 +271,79 @@ static void error(char *x) | |||
271 | asm("hlt"); | 271 | asm("hlt"); |
272 | } | 272 | } |
273 | 273 | ||
274 | #if CONFIG_X86_NEED_RELOCS | ||
275 | static void handle_relocations(void *output, unsigned long output_len) | ||
276 | { | ||
277 | int *reloc; | ||
278 | unsigned long delta, map, ptr; | ||
279 | unsigned long min_addr = (unsigned long)output; | ||
280 | unsigned long max_addr = min_addr + output_len; | ||
281 | |||
282 | /* | ||
283 | * Calculate the delta between where vmlinux was linked to load | ||
284 | * and where it was actually loaded. | ||
285 | */ | ||
286 | delta = min_addr - LOAD_PHYSICAL_ADDR; | ||
287 | if (!delta) { | ||
288 | debug_putstr("No relocation needed... "); | ||
289 | return; | ||
290 | } | ||
291 | debug_putstr("Performing relocations... "); | ||
292 | |||
293 | /* | ||
294 | * The kernel contains a table of relocation addresses. Those | ||
295 | * addresses have the final load address of the kernel in virtual | ||
296 | * memory. We are currently working in the self map. So we need to | ||
297 | * create an adjustment for kernel memory addresses to the self map. | ||
298 | * This will involve subtracting out the base address of the kernel. | ||
299 | */ | ||
300 | map = delta - __START_KERNEL_map; | ||
301 | |||
302 | /* | ||
303 | * Process relocations: 32 bit relocations first then 64 bit after. | ||
304 | * Two sets of binary relocations are added to the end of the kernel | ||
305 | * before compression. Each relocation table entry is the kernel | ||
306 | * address of the location which needs to be updated stored as a | ||
307 | * 32-bit value which is sign extended to 64 bits. | ||
308 | * | ||
309 | * Format is: | ||
310 | * | ||
311 | * kernel bits... | ||
312 | * 0 - zero terminator for 64 bit relocations | ||
313 | * 64 bit relocation repeated | ||
314 | * 0 - zero terminator for 32 bit relocations | ||
315 | * 32 bit relocation repeated | ||
316 | * | ||
317 | * So we work backwards from the end of the decompressed image. | ||
318 | */ | ||
319 | for (reloc = output + output_len - sizeof(*reloc); *reloc; reloc--) { | ||
320 | int extended = *reloc; | ||
321 | extended += map; | ||
322 | |||
323 | ptr = (unsigned long)extended; | ||
324 | if (ptr < min_addr || ptr > max_addr) | ||
325 | error("32-bit relocation outside of kernel!\n"); | ||
326 | |||
327 | *(uint32_t *)ptr += delta; | ||
328 | } | ||
329 | #ifdef CONFIG_X86_64 | ||
330 | for (reloc--; *reloc; reloc--) { | ||
331 | long extended = *reloc; | ||
332 | extended += map; | ||
333 | |||
334 | ptr = (unsigned long)extended; | ||
335 | if (ptr < min_addr || ptr > max_addr) | ||
336 | error("64-bit relocation outside of kernel!\n"); | ||
337 | |||
338 | *(uint64_t *)ptr += delta; | ||
339 | } | ||
340 | #endif | ||
341 | } | ||
342 | #else | ||
343 | static inline void handle_relocations(void *output, unsigned long output_len) | ||
344 | { } | ||
345 | #endif | ||
346 | |||
274 | static void parse_elf(void *output) | 347 | static void parse_elf(void *output) |
275 | { | 348 | { |
276 | #ifdef CONFIG_X86_64 | 349 | #ifdef CONFIG_X86_64 |
@@ -325,7 +398,8 @@ static void parse_elf(void *output) | |||
325 | asmlinkage void decompress_kernel(void *rmode, memptr heap, | 398 | asmlinkage void decompress_kernel(void *rmode, memptr heap, |
326 | unsigned char *input_data, | 399 | unsigned char *input_data, |
327 | unsigned long input_len, | 400 | unsigned long input_len, |
328 | unsigned char *output) | 401 | unsigned char *output, |
402 | unsigned long output_len) | ||
329 | { | 403 | { |
330 | real_mode = rmode; | 404 | real_mode = rmode; |
331 | 405 | ||
@@ -365,6 +439,7 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap, | |||
365 | debug_putstr("\nDecompressing Linux... "); | 439 | debug_putstr("\nDecompressing Linux... "); |
366 | decompress(input_data, input_len, NULL, NULL, output, NULL, error); | 440 | decompress(input_data, input_len, NULL, NULL, output, NULL, error); |
367 | parse_elf(output); | 441 | parse_elf(output); |
442 | handle_relocations(output, output_len); | ||
368 | debug_putstr("done.\nBooting the kernel.\n"); | 443 | debug_putstr("done.\nBooting the kernel.\n"); |
369 | return; | 444 | return; |
370 | } | 445 | } |
diff --git a/arch/x86/include/asm/page_32_types.h b/arch/x86/include/asm/page_32_types.h index ef17af013475..f48b17df4224 100644 --- a/arch/x86/include/asm/page_32_types.h +++ b/arch/x86/include/asm/page_32_types.h | |||
@@ -15,6 +15,8 @@ | |||
15 | */ | 15 | */ |
16 | #define __PAGE_OFFSET _AC(CONFIG_PAGE_OFFSET, UL) | 16 | #define __PAGE_OFFSET _AC(CONFIG_PAGE_OFFSET, UL) |
17 | 17 | ||
18 | #define __START_KERNEL_map __PAGE_OFFSET | ||
19 | |||
18 | #define THREAD_SIZE_ORDER 1 | 20 | #define THREAD_SIZE_ORDER 1 |
19 | #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) | 21 | #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) |
20 | 22 | ||
diff --git a/arch/x86/include/asm/page_64_types.h b/arch/x86/include/asm/page_64_types.h index 6c896fbe21db..43dcd804ebd5 100644 --- a/arch/x86/include/asm/page_64_types.h +++ b/arch/x86/include/asm/page_64_types.h | |||
@@ -32,11 +32,6 @@ | |||
32 | */ | 32 | */ |
33 | #define __PAGE_OFFSET _AC(0xffff880000000000, UL) | 33 | #define __PAGE_OFFSET _AC(0xffff880000000000, UL) |
34 | 34 | ||
35 | #define __PHYSICAL_START ((CONFIG_PHYSICAL_START + \ | ||
36 | (CONFIG_PHYSICAL_ALIGN - 1)) & \ | ||
37 | ~(CONFIG_PHYSICAL_ALIGN - 1)) | ||
38 | |||
39 | #define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START) | ||
40 | #define __START_KERNEL_map _AC(0xffffffff80000000, UL) | 35 | #define __START_KERNEL_map _AC(0xffffffff80000000, UL) |
41 | 36 | ||
42 | /* See Documentation/x86/x86_64/mm.txt for a description of the memory map. */ | 37 | /* See Documentation/x86/x86_64/mm.txt for a description of the memory map. */ |
diff --git a/arch/x86/include/asm/page_types.h b/arch/x86/include/asm/page_types.h index 54c97879195e..f97fbe3abb67 100644 --- a/arch/x86/include/asm/page_types.h +++ b/arch/x86/include/asm/page_types.h | |||
@@ -33,6 +33,11 @@ | |||
33 | (((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0 ) | \ | 33 | (((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0 ) | \ |
34 | VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) | 34 | VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) |
35 | 35 | ||
36 | #define __PHYSICAL_START ALIGN(CONFIG_PHYSICAL_START, \ | ||
37 | CONFIG_PHYSICAL_ALIGN) | ||
38 | |||
39 | #define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START) | ||
40 | |||
36 | #ifdef CONFIG_X86_64 | 41 | #ifdef CONFIG_X86_64 |
37 | #include <asm/page_64_types.h> | 42 | #include <asm/page_64_types.h> |
38 | #else | 43 | #else |