ELF Relocatable x86 and x86_64 bzImages
Subsystems (2)
The problem:
We can't always run the kernel at 1MB or 2MB, and so people who need different addresses must build multiple kernels. The bzImage format can't even represent loading a kernel at other than it's default address. With kexec on panic now starting to be used by distros having a kernel not running at the default load address is starting to become common.
The goal of this patch series is to build kernels that are relocatable at run time, and to extend the bzImage format to make it capable of expressing a relocatable kernel.
In extending the bzImage format I am replacing the existing unused bootsector with an ELF header. To express what is going on the ELF header will have type ET_DYN. Just like the kernel loading an ET_DYN executable bootloaders are not expected to process relocations. But the executable may be shifted in the address space so long as it's alignment requirements are met.
The x86_64 kernel is simply built to live at a fixed virtual address and the boot page tables are relocated. The i386 kernel is built to process relocations generated with --embedded-relocs (after vmlinux.lds.S) has been fixed up to sort out static and dynamic relocations.
Currently there are 33 patches in my tree to do this.
The weirdest symptom I have had so far is that page faults did not trigger the early exception handler on x86_64 (instead I got a reboot).
There is one outstanding issue where I am probably requiring too much alignment on the arch/i386 kernel.
Can anyone find anything else?
Eric
PATCH 1/33 i386: vmlinux.lds.S Distinguish absolute symbols
Ld knows about 2 kinds of symbols, absolute and section relative. Section relative symbols symbols change value when a section is moved and absolute symbols do not.
Currently in the linker script we have several labels marking the beginning and ending of sections that are outside of sections, making them absolute symbols. Having a mixture of absolute and section relative symbols refereing to the same data is currently harmless but it is confusing.
This must be done carefully as newer revs of ld do not place symbols that appear in sections without data and instead ld makes those symbols global :(
My ultimate goal is to build a relocatable kernel. The safest and least intrusive technique is to generate relocation entries so the kernel can be relocated at load time. The only penalty would be an increase in the size of the kernel binary. The problem is that if absolute and relocatable symbols are not properly specified absolute symbols will be relocated or section relative symbols won't be, which is fatal.
The practical motivation is that when generating kernels that will run from a reserved area for analyzing what caused a kernel panic, it is simpler if you don't need to hard code the physical memory location they will run at, especially for the distributions.
--- arch/i386/kernel/vmlinux.lds.S | 111 ++++++++++++++++++++----------------- include/asm-generic/vmlinux.lds.h | 2 - 2 files changed, 60 insertions(+), 53 deletions(-)
arch/i386/kernel/vmlinux.lds.S +59 -52
@@ -18,43 +18,46 @@ SECTIONS . = __KERNEL_START; phys_startup_32 = startup_32 - LOAD_OFFSET; /* read-only */ - _text = .; /* Text and read-only data */ .text : AT(ADDR(.text) - LOAD_OFFSET) { + _text = .; /* Text and read-only data */ *(.text) SCHED_TEXT LOCK_TEXT KPROBES_TEXT *(.fixup) *(.gnu.warning) - } = 0x9090 - - _etext = .; /* End of text section */ + _etext = .; /* End of text section */ + } = 0x9090 . = ALIGN(16); /* Exception table */ - __start___ex_table = .; - __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) } - __stop___ex_table = .; + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + } RODATA . = ALIGN(4); - __tracedata_start = .; .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) { + __tracedata_start = .; *(.tracedata) + __tracedata_end = .; } - __tracedata_end = .; /* writeable */ .data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */ *(.data) CONSTRUCTORS - } + } . = ALIGN(4096); - __nosave_begin = .; - .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { *(.data.nosave) } - . = ALIGN(4096); - __nosave_end = .; + .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { + __nosave_begin = .; + *(.data.nosave) + . = ALIGN(4096); + __nosave_end = .; + } . = ALIGN(4096); .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
@@ -68,8 +71,10 @@ SECTIONS /* rarely changed data like cpu maps */ . = ALIGN(32); - .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) { *(.data.read_mostly) } - _edata = .; /* End of data section */ + .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) { + *(.data.read_mostly) + _edata = .; /* End of data section */ + } #ifdef CONFIG_STACK_UNWIND . = ALIGN(4);
@@ -87,39 +92,41 @@ #endif /* might get freed after init */ . = ALIGN(4096); - __smp_alt_begin = .; - __smp_alt_instructions = .; .smp_altinstructions : AT(ADDR(.smp_altinstructions) - LOAD_OFFSET) { + __smp_alt_begin = .; + __smp_alt_instructions = .; *(.smp_altinstructions) + __smp_alt_instructions_end = .; } - __smp_alt_instructions_end = .; . = ALIGN(4); - __smp_locks = .; .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) { + __smp_locks = .; *(.smp_locks) + __smp_locks_end = .; } - __smp_locks_end = .; .smp_altinstr_replacement : AT(ADDR(.smp_altinstr_replacement) - LOAD_OFFSET) { *(.smp_altinstr_replacement) + . = ALIGN(4096); + __smp_alt_end = .; } - . = ALIGN(4096); - __smp_alt_end = .; /* will be freed after init */ . = ALIGN(4096); /* Init code and data */ - __init_begin = .; .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { + __init_begin = .; _sinittext = .; *(.init.text) _einittext = .; } .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) } . = ALIGN(16); - __setup_start = .; - .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { *(.init.setup) } - __setup_end = .; - __initcall_start = .; + .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { + __setup_start = .; + *(.init.setup) + __setup_end = .; + } .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) { + __initcall_start = .; *(.initcall1.init) *(.initcall2.init) *(.initcall3.init)
@@ -127,20 +134,20 @@ #endif *(.initcall5.init) *(.initcall6.init) *(.initcall7.init) + __initcall_end = .; } - __initcall_end = .; - __con_initcall_start = .; .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) { + __con_initcall_start = .; *(.con_initcall.init) + __con_initcall_end = .; } - __con_initcall_end = .; SECURITY_INIT . = ALIGN(4); - __alt_instructions = .; .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) { + __alt_instructions = .; *(.altinstructions) + __alt_instructions_end = .; } - __alt_instructions_end = .; .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) { *(.altinstr_replacement) }
@@ -149,32 +156,32 @@ #endif .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { *(.exit.text) } .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) } . = ALIGN(4096); - __initramfs_start = .; - .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { *(.init.ramfs) } - __initramfs_end = .; + .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { + __initramfs_start = .; + *(.init.ramfs) + __initramfs_end = .; + } . = ALIGN(L1_CACHE_BYTES); - __per_cpu_start = .; - .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { *(.data.percpu) } - __per_cpu_end = .; + .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { + __per_cpu_start = .; + *(.data.percpu) + __per_cpu_end = .; + } . = ALIGN(4096); - __init_end = .; /* freed after init ends here */ - __bss_start = .; /* BSS */ - .bss.page_aligned : AT(ADDR(.bss.page_aligned) - LOAD_OFFSET) { - *(.bss.page_aligned) - } .bss : AT(ADDR(.bss) - LOAD_OFFSET) { + __init_end = .; + __bss_start = .; /* BSS */ + *(.bss.page_aligned) *(.bss) + . = ALIGN(4); + __bss_stop = .; + _end = . ; + /* This is where the kernel creates the early boot page tables */ + . = ALIGN(4096); + pg0 = . ; } - . = ALIGN(4); - __bss_stop = .; - - _end = . ; - - /* This is where the kernel creates the early boot page tables */ - . = ALIGN(4096); - pg0 = .; /* Sections to be discarded */ /DISCARD/ : {
include/asm-generic/vmlinux.lds.h +1 -1
@@ -11,8 +11,8 @@ #define ALIGN_FUNCTION() . = ALIGN(8)#define RODATA \ . = ALIGN(4096); \ - __start_rodata = .; \ .rodata : AT(ADDR(.rodata) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start_rodata) = .; \ *(.rodata) *(.rodata.*) \ *(__vermagic)/* Kernel version magic */ \ } \
Signature · 1 line
1.4.2.rc2.g5209e
Re: [PATCH 1/33] i386: vmlinux.lds.S Distinguish absolute symbols
Quoted 10 lines · Eric W. Biederman
Ld knows about 2 kinds of symbols, absolute and section relative. Section relative symbols symbols change value when a section is moved and absolute symbols do not.
Currently in the linker script we have several labels marking the beginning and ending of sections that are outside of sections, making them absolute symbols. Having a mixture of absolute and section relative symbols refereing to the same data is currently harmless but it is confusing.
In the past we have seen problems when there was some padding between the global symbol and the actual section start. The reason for the padding was the alignment of the section which is aligned accordign to the longest of the contained symbols. So no matter the relocatable kernel this is an improvement.
Sam
PATCH 2/33 i386: define __pa_symbol
In reply to Eric W. BiedermanOn x86_64 we have to be careful with calculating the physical address of kernel symbols. Both because of compiler odditities and because the symbols live in a different range of the virtual address space.
Having a defintition of __pa_symbol that works on both x86_64 and i386 simplifies writing code that works for both x86_64 and i386 that has these kinds of dependencies.
So this patch adds the trivial i386 __pa_symbol definition.
--- include/asm-i386/page.h | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
include/asm-i386/page.h +1 -0
@@ -124,6 +124,7 @@ #define PAGE_OFFSET ((unsigned long)__P#define VMALLOC_RESERVE ((unsigned long)__VMALLOC_RESERVE)#define MAXMEM (-__PAGE_OFFSET-__VMALLOC_RESERVE)#define __pa (x) ((unsigned long)(x)-PAGE_OFFSET) +#define __pa_symbol (x) __pa(x)#define __va (x) ((void *)((unsigned long)(x)+PAGE_OFFSET))#define pfn_to_kaddr (pfn) __va((pfn) << PAGE_SHIFT)#ifdef CONFIG_FLATMEM
Signature · 1 line
1.4.2.rc2.g5209e
Re: [PATCH 2/33] i386: define __pa_symbol
Quoted 21 lines · Eric W. Biederman
On
x86_64we have to be careful with calculating the physical address of kernel symbols. Both because of compiler odditities and because the symbols live in a different range of the virtual address space.Having a defintition of
__pa_symbolthat works on bothx86_64and i386 simplifies writing code that works for bothx86_64and i386 that has these kinds of dependencies.So this patch adds the trivial i386
__pa_symboldefinition.Signed-off-by Eric W. Biederman <[email protected]>--- include/asm-i386/page.h | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)include/asm-i386/page.h +0
-0
include/asm-i386/page.h #define PAGE_OFFSET ((unsigned long)__P · line 127
Quoted 4 lines
include/asm-i386/page.h +1
-0@@ -124,6 +124,7 @@ #define PAGE_OFFSET ((unsigned long)__P#define VMALLOC_RESERVE ((unsigned long)__VMALLOC_RESERVE)#define MAXMEM (-__PAGE_OFFSET-__VMALLOC_RESERVE)#define __pa (x) ((unsigned long)(x)-PAGE_OFFSET) +#define __pa_symbol (x) __pa(x)
Actually PAGE_OFFSET arithmetic on symbols is outside ISO C and gcc misoptimizes it occassionally. You would need to use HIDE_RELOC or similar. That is why x86-64 has the magic.
-Andi
Re: [PATCH 2/33] i386: define __pa_symbol
Quoted 18 lines · Andi Kleen
Quoted 16 lines · Eric W. Biederman
On
x86_64we have to be careful with calculating the physical address of kernel symbols. Both because of compiler odditities and because the symbols live in a different range of the virtual address space.Having a defintition of
__pa_symbolthat works on bothx86_64and i386 simplifies writing code that works for bothx86_64and i386 that has these kinds of dependencies.So this patch adds the trivial i386
__pa_symboldefinition.Signed-off-by Eric W. Biederman <[email protected]>--- include/asm-i386/page.h | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
Quoted 13 lines
include/asm-i386/page.h #define PAGE_OFFSET ((unsigned long)__P · line 127
Quoted 9 lines
include/asm-i386/page.h +1
-0@@ -124,6 +124,7 @@ #define PAGE_OFFSET ((unsigned long)__P#define VMALLOC_RESERVE ((unsigned long)__VMALLOC_RESERVE)#define MAXMEM (-__PAGE_OFFSET-__VMALLOC_RESERVE)#define __pa (x) ((unsigned long)(x)-PAGE_OFFSET) +#define __pa_symbol (x) __pa(x)Actually
PAGE_OFFSETarithmetic on symbols is outside ISO C and gcc misoptimizes it occassionally. You would need to useHIDE_RELOCor similar. That is why x86-64 has the magic.
Yes. ISO C only defines pointer arithmetic with in arrays. I believe gnu C makes it a well defined case.
Currently we do not appear to have any problems on i386. But I have at least one case of code that is shared between i386 and x86_64 and it is appropriate to use __pa_symbol on x86_64.
So I added __pa_symbol for that practical reason.
I would have no problems with generalizing this but I wanted to at least make it possible to use the concept on i386.
I will be happy to add in the assembly magic, if you don't have any other problems with this.
Eric
Re: [PATCH 2/33] i386: define __pa_symbol
Quoted 3 lines
Yes. ISO C only defines pointer arithmetic with in arrays. I believe gnu C makes it a well defined case.
Nope, it doesn't.
There was a miscompilation on PPC some time ago, that is why HIDE_RELOC() and __pa_symbol() was implemented.
Quoted 10 lines
Currently we do not appear to have any problems on i386. But I have at least one case of code that is shared between i386 and
x86_64and it is appropriate to use__pa_symbolonx86_64.So I added
__pa_symbolfor that practical reason.I would have no problems with generalizing this but I wanted to at least make it possible to use the concept on i386.
No problem with that, just use HIDE_RELOC
-Andi
PATCH 3/33 i386 setup.c: Reserve kernel memory starting from _text
In reply to Eric W. BiedermanCurrently when we are reserving the memory the kernel text resides in we start at __PHYSICAL_START which happens to be correct but not very obvious. In addition when we start relocating the kernel __PHYSICAL_START is the wrong value, as it is an absolute symbol that does not get relocated.
By starting the reservation at __pa_symbol(_text) the code is clearer and will be correct when relocated.
--- arch/i386/kernel/setup.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
arch/i386/kernel/setup.c +2 -2
@@ -1219,8 +1219,8 @@ void __init setup_bootmem_allocator(void* the (very unlikely) case of us accidentally initializing the * bootmem allocator with an invalid RAM area. */ -reserve_bootmem (__PHYSICAL_START, (PFN_PHYS (min_low_pfn) + - bootmap_size +PAGE_SIZE -1 ) - (__PHYSICAL_START)); +reserve_bootmem (__pa_symbol (_text), (PFN_PHYS (min_low_pfn) + + bootmap_size +PAGE_SIZE -1 ) -__pa_symbol (_text));/* * reserve physical page 0 - it's a special BIOS page on many boxes,
Signature · 1 line
1.4.2.rc2.g5209e
PATCH 4/33 i386: CONFIG_PHYSICAL_START cleanup
In reply to Eric W. BiedermanDefining __PHYSICAL_START and __KERNEL_START in asm-i386/page.h works but it triggers a full kernel rebuild for the silliest of reasons. This modifies the users to directly use CONFIG_PHYSICAL_START and linux/config.h which prevents the full rebuild problem, which makes the code much more maintainer and hopefully user friendly.
--- arch/i386/boot/compressed/head.S | 8 ++++---- arch/i386/boot/compressed/misc.c | 8 ++++---- arch/i386/kernel/vmlinux.lds.S | 3 ++- include/asm-i386/page.h | 3 --- 4 files changed, 10 insertions(+), 12 deletions(-)
arch/i386/boot/compressed/head.S +4 -4
@@ -23,9 +23,9 @@ */ .text +#include <linux/config.h> #include <linux/linkage.h> #include <asm/segment.h> -#include <asm/page.h> .globl startup_32
@@ -75,7 +75,7 @@ startup_32: popl %esi # discard address popl %esi # real mode pointer xorl %ebx,%ebx - ljmp $(__BOOT_CS), $__PHYSICAL_START + ljmp $(__BOOT_CS), $CONFIG_PHYSICAL_START /* * We come here, if we were loaded high.
@@ -100,7 +100,7 @@ startup_32: popl %ecx # lcount popl %edx # high_buffer_start popl %eax # hcount - movl $__PHYSICAL_START,%edi + movl $CONFIG_PHYSICAL_START,%edi cli # make sure we don't get interrupted ljmp $(__BOOT_CS), $0x1000 # and jump to the move routine
@@ -125,5 +125,5 @@ move_routine_start: movsl movl %ebx,%esi # Restore setup pointer xorl %ebx,%ebx - ljmp $(__BOOT_CS), $__PHYSICAL_START + ljmp $(__BOOT_CS), $CONFIG_PHYSICAL_START move_routine_end:
arch/i386/boot/compressed/misc.c +4 -4
@@ -9,11 +9,11 @@* High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 */ +#include <linux/config.h> #include <linux/linkage.h> #include <linux/vmalloc.h> #include <linux/screen_info.h> #include <asm/io.h> -#include <asm/page.h> /* * gzip declarations
@@ -303,7 +303,7 @@ #ifdef STANDARD_MEMORY_BIOS_CALL#else if ((RM_ALT_MEM_K >RM_EXT_MEM_K ?RM_ALT_MEM_K :RM_EXT_MEM_K ) <1024 )error ("Less than 2MB of memory" );#endif - output_data = (unsigned char *)__PHYSICAL_START;/* Normally Points to 1M */ + output_data = (unsigned char *)CONFIG_PHYSICAL_START ;/* Normally Points to 1M */ free_mem_end_ptr = (long )real_mode; }
@@ -326,8 +326,8 @@ #endif low_buffer_size = low_buffer_end -LOW_BUFFER_START ; high_loaded =1 ; free_mem_end_ptr = (long )high_buffer_start; -if ( (__PHYSICAL_START + low_buffer_size) > ((ulg )high_buffer_start)) { - high_buffer_start = (uch *)(__PHYSICAL_START + low_buffer_size); +if ( (CONFIG_PHYSICAL_START + low_buffer_size) > ((ulg )high_buffer_start)) { + high_buffer_start = (uch *)(CONFIG_PHYSICAL_START + low_buffer_size); mv->hcount =0 ;/* say: we need not to move high_buffer */ }else mv->hcount =-1 ;
arch/i386/kernel/vmlinux.lds.S +2 -1
@@ -4,6 +4,7 @@ #define LOAD_OFFSET __PAGE_OFFSET +#include <linux/config.h> #include <asm-generic/vmlinux.lds.h> #include <asm/thread_info.h> #include <asm/page.h>
@@ -15,7 +16,7 @@ ENTRY(phys_startup_32) jiffies = jiffies_64; SECTIONS { - . = __KERNEL_START; + . = LOAD_OFFSET + CONFIG_PHYSICAL_START; phys_startup_32 = startup_32 - LOAD_OFFSET; /* read-only */ .text : AT(ADDR(.text) - LOAD_OFFSET) {
include/asm-i386/page.h +0 -3
@@ -112,12 +112,9 @@ #endif /* __ASSEMBLY__ */#ifdef __ASSEMBLY__#define __PAGE_OFFSET CONFIG_PAGE_OFFSET -#define __PHYSICAL_START CONFIG_PHYSICAL_START#else #define __PAGE_OFFSET ((unsigned long)CONFIG_PAGE_OFFSET) -#define __PHYSICAL_START ((unsigned long)CONFIG_PHYSICAL_START)#endif -#define __KERNEL_START (__PAGE_OFFSET + __PHYSICAL_START)#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
Signature · 1 line
1.4.2.rc2.g5209e
Re: [PATCH 4/33] i386: CONFIG_PHYSICAL_START cleanup
Quoted 19 lines · Eric W. Biederman
Defining
__PHYSICAL_STARTand__KERNEL_STARTinasm-i386/page.hworks but it triggers a full kernel rebuild for the silliest of reasons. This modifies the users to directly useCONFIG_PHYSICAL_STARTandlinux/config.hwhich prevents the full rebuild problem, which makes the code much more maintainer and hopefully user friendly.Signed-off-by Eric W. Biederman <[email protected]>--- arch/i386/boot/compressed/head.S | 8 ++++---- arch/i386/boot/compressed/misc.c | 8 ++++---- arch/i386/kernel/vmlinux.lds.S | 3 ++- include/asm-i386/page.h | 3 --- 4 files changed, 10 insertions(+), 12 deletions(-)arch/i386/boot/compressed/head.S +0
-0
arch/i386/boot/compressed/head.S line 26
Quoted 4 lines
arch/i386/boot/compressed/head.S +1
-0@@ -23,9 +23,9 @@ */ .text +#include <linux/config.h>
You already have full access to all CONFIG_* symbols - kbuild includes it on the commandline. So please kill this include.
Sam
Re: [PATCH 4/33] i386: CONFIG_PHYSICAL_START cleanup
Quoted 9 lines · Sam Ravnborg
Review
Quoted 1 line
(quoted diff) +0
-0
b/arch/i386/boot/compressed/head.SQuoted 7 lines
index b5893e4..8f28ecd 100644
arch/i386/boot/compressed/head.S +0
-0@@ -23,9 +23,9 @@ */ .text
Quoted 4 lines
arch/i386/boot/compressed/head.S line 26
Quoted 1 line
arch/i386/boot/compressed/head.S +1
-0+#include <linux/config.h>You already have full access to all CONFIG_* symbols - kbuild includes it on the commandline. So please kill this include.
Ok. That must be new. No problem.
Eric
Re: [PATCH 4/33] i386: CONFIG_PHYSICAL_START cleanup
In reply to Sam RavnborgQuoted 24 lines · Sam Ravnborg
Quoted 7 lines · Eric W. Biederman
Defining
__PHYSICAL_STARTand__KERNEL_STARTinasm-i386/page.hworks but it triggers a full kernel rebuild for the silliest of reasons. This modifies the users to directly useCONFIG_PHYSICAL_STARTandlinux/config.hwhich prevents the full rebuild problem, which makes the code much more maintainer and hopefully user friendly.Signed-off-by Eric W. Biederman <[email protected]>Review
Quoted 8 lines
--- arch/i386/boot/compressed/head.S | 8 ++++---- arch/i386/boot/compressed/misc.c | 8 ++++---- arch/i386/kernel/vmlinux.lds.S | 3 ++- include/asm-i386/page.h | 3 --- 4 files changed, 10 insertions(+), 12 deletions(-)(quoted diff) +0
-0
b/arch/i386/boot/compressed/head.SQuoted 7 lines
index b5893e4..8f28ecd 100644
arch/i386/boot/compressed/head.S +0
-0@@ -23,9 +23,9 @@ */ .text
Quoted 4 lines
arch/i386/boot/compressed/head.S line 26
Quoted 1 line
arch/i386/boot/compressed/head.S +1
-0+#include <linux/config.h>You already have full access to all CONFIG_* symbols - kbuild includes it on the commandline. So please kill this include.
Stupid questions:
- Why do we still have a linux/config.h if it is totally redundant.
- Why don't we have at least a #warning in linux/config.h that would tell us not to include it.
- Why do we still have about 200 includes of linux/config.h in the kernel tree?
I would much rather have a compile error, or at least a compile warning rather than needed a code review to notice this error.
We haven't needed this header since october of last year.
Eric
Re: [PATCH 4/33] i386: CONFIG_PHYSICAL_START cleanup
Quoted 10 lines
Stupid questions:
- Why do we still have alinux/config.hif it is totally redundant.
- Why don't we have at least a #warning inlinux/config.hthat would tell us not to include it.
- Why do we still have about 200 includes oflinux/config.hin the kernel tree?I would much rather have a compile error, or at least a compile warning rather than needed a code review to notice this error.
In progress. As part of the ongoing header cleanup all include <config.h> are being removed and a warning is included in config.h.
When the change was done I did not want to spew out thousands of warning for a simple thing like this.
Sam
PATCH 5/33 i386 Kconfig: Add a range definition to config PHYSICAL_START
In reply to Eric W. BiedermanThe kernels physical start address must fall in the first 1GB on i386. This just adds a small range definition to enforce that.
--- arch/i386/Kconfig | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
arch/i386/Kconfig +1 -0
@@ -766,6 +766,7 @@ config PHYSICAL_START default "0x1000000" if CRASH_DUMP default "0x100000" + range 0x100000 0x37c00000 help This gives the physical address where the kernel is loaded. Normally for regular kernels this value is 0x100000 (1MB). But in the case
Signature · 1 line
1.4.2.rc2.g5209e
PATCH 6/33 Make linux/elf.h safe to be included in assembly files
In reply to Eric W. BiedermanThe motivation for this is that currently we have 512 bytes at the begining of a bzImage that are unused now that we don't have a bootsector there. I plan on putting an ELF header there, and generating it by hand with assebmly data directives to be minimally disrutptive to the current build process.
To do that I need the elf magic constants available to my assembly code.
--- include/linux/elf.h | 22 +++++++++++++++++++++- 1 files changed, 21 insertions(+), 1 deletions(-)
include/linux/elf.h +21 -1
@@ -1,9 +1,11 @@#ifndef _LINUX_ELF_H#define _LINUX_ELF_H +#include <linux/elf-em.h> + +#ifndef __ASSEMBLY__#include <linux/types.h> #include <linux/auxvec.h> -#include <linux/elf-em.h> #include <asm/elf.h> #ifndef elf_read_implies_exec
@@ -30,6 +32,8 @@ typedef __u32 Elf64_Word;typedef __u64 Elf64_Xword ;typedef __s64 Elf64_Sxword ; +#endif /* __ASSEMBLY__ */ +/* These constants are for the segment types stored in the image headers */ #define PT_NULL 0#define PT_LOAD 1
@@ -97,6 +101,8 @@ #define STT_FILE 4#define STT_COMMON 5#define STT_TLS 6 +#ifndef __ASSEMBLY__ +#define ELF_ST_BIND (x) ((x) >> 4)#define ELF_ST_TYPE (x) (((unsigned int) x) & 0xf)#define ELF32_ST_BIND (x) ELF_ST_BIND(x)
@@ -204,12 +210,16 @@ typedef struct elf64_hdr {Elf64_Half e_shstrndx; } Elf64_Ehdr; +#endif /* __ASSEMBLY__ */ +/* These constants define the permissions on sections in the program header, p_flags. */ #define PF_R 0x4#define PF_W 0x2#define PF_X 0x1 +#ifndef __ASSEMBLY__ + typedef struct elf32_phdr{ Elf32_Word p_type; Elf32_Off p_offset;
@@ -232,6 +242,8 @@ typedef struct elf64_phdr { Elf64_Xword p_align; /* Segment alignment, file & memory */ } Elf64_Phdr; +#endif /* __ASSEMBLY__ */ +/* sh_type */ #define SHT_NULL 0#define SHT_PROGBITS 1
@@ -265,6 +277,8 @@ #define SHN_HIPROC 0xff1f#define SHN_ABS 0xfff1#define SHN_COMMON 0xfff2#define SHN_HIRESERVE 0xffff + +#ifndef __ASSEMBLY__ typedef struct { Elf32_Word sh_name;
@@ -292,6 +306,8 @@ typedef struct elf64_shdr { Elf64_Xword sh_entsize; /* Entry size if section holds table */ } Elf64_Shdr; +#endif /* __ASSEMBLY__ */ +#define EI_MAG0 0/* e_ident[] indexes */ #define EI_MAG1 1#define EI_MAG2 2
@@ -338,6 +354,8 @@ #define NT_AUXV 6#define NT_PRXFPREG 0x46e62b7f/* copied from gdb5.1/include/elf/common.h */ +#ifndef __ASSEMBLY__ + /* Note header in a PT_NOTE section */ typedef struct elf32_note { Elf32_Word n_namesz; /* Name size */
@@ -368,5 +386,7 @@ #define elf_note elf64_note#endif +#endif /* __ASSEMBLY__ */ +#endif /* _LINUX_ELF_H */
Signature · 1 line
1.4.2.rc2.g5209e
PATCH 7/33 elf: Add ELFOSABI_STANDALONE to elf.h
In reply to Eric W. Biederman--- include/linux/elf.h | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-)
include/linux/elf.h +3 -2
@@ -338,8 +338,9 @@ #define EV_NONE 0 /* e_version, EI_VER#define EV_CURRENT 1#define EV_NUM 2 -#define ELFOSABI_NONE 0 -#define ELFOSABI_LINUX 3 +#define ELFOSABI_NONE 0 +#define ELFOSABI_LINUX 3 +#define ELFOSABI_STANDALONE 255#ifndef ELF_OSABI #define ELF_OSABI ELFOSABI_NONE
Signature · 1 line
1.4.2.rc2.g5209e
PATCH 8/33 kallsyms.c: Generate relocatable symbols.
In reply to Eric W. BiedermanPrint the addresses of non-absolute symbols relative to _text so that ld will generate relocations. Allowing a relocatable kernel to relocate them. We can't actually use the symbol names because kallsyms includes static symbols that are not exported from their object files.
--- scripts/kallsyms.c | 20 +++++++++++++++++--- 1 files changed, 17 insertions(+), 3 deletions(-)
scripts/kallsyms.c +17 -3
@@ -43,7 +43,7 @@ struct sym_entry {static struct sym_entry *table;static unsigned int table_size, table_cnt; -static unsigned long long _stext, _etext, _sinittext, _einittext, _sextratext, _eextratext; +static unsigned long long _text, _stext, _etext, _sinittext, _einittext, _sextratext, _eextratext;static int all_symbols =0 ;static char symbol_prefix_char ='\0' ;
@@ -91,7 +91,9 @@ static int read_symbol(FILE *in, struct sym++;/* Ignore most absolute/undefined (?) symbols. */ -if (strcmp (sym,"_stext" ) ==0 ) +if (strcmp (sym,"_text" ) ==0 ) + _text = s->addr; +else if (strcmp (sym,"_stext" ) ==0 ) _stext = s->addr;else if (strcmp (sym,"_etext" ) ==0 ) _etext = s->addr;
@@ -265,9 +267,21 @@ static void write_src(void)printf (".data\n" ); +/* Provide proper symbols relocatability by their '_text' +* relativeness. The symbol names cannot be used to construct +* normal symbol references as the list of symbols contains +* symbols that are declared static and are private to their +* .o files. This prevents .tmp_kallsyms.o or any other +* object from referencing them. +*/ output_label ("kallsyms_addresses" );for (i =0 ; i < table_cnt; i++) { -printf ("\tPTR\t%#llx\n" , table[i].addr); +if (toupper (table[i].sym[0 ]) !='A' ) { +printf ("\tPTR\t_text + %#llx\n" , + table[i].addr - _text); + }else { +printf ("\tPTR\t%#llx\n" , table[i].addr); + } }printf ("\n" );
Signature · 1 line
1.4.2.rc2.g5209e
Re: [PATCH 8/33] kallsyms.c: Generate relocatable symbols.
Quoted 7 lines · Eric W. Biederman
Print the addresses of non-absolute symbols relative to
_textso that ld will generate relocations. Allowing a relocatable kernel to relocate them. We can't actually use the symbol names because kallsyms includes static symbols that are not exported from their object files.[...]
scripts/kallsyms.c static void write_src(void) · line 284
Quoted 9 lines
scripts/kallsyms.c +6
-1output_label ("kallsyms_addresses" );for (i =0 ; i < table_cnt; i++) { -printf ("\tPTR\t%#llx\n" , table[i].addr); +if (toupper (table[i].sym[0 ]) !='A' ) { +printf ("\tPTR\t_text + %#llx\n" , + table[i].addr - _text); + }else { +printf ("\tPTR\t%#llx\n" , table[i].addr); + }
Doesn't this break kallsyms for almost everyone?
kallsyms addresses aren't used just for displaying, but also to find symbols from their addresses (from the stack trace, etc.).
Am I missing something?
Signature · 4 lines
Paulo Marques - www.grupopie.com "The face of a child can say it all, especially the mouth part of the face."
Re: [PATCH 8/33] kallsyms.c: Generate relocatable symbols.
Quoted 19 lines · Paulo Marques
Quoted 6 lines · Eric W. Biederman
Print the addresses of non-absolute symbols relative to
_textso that ld will generate relocations. Allowing a relocatable kernel to relocate them. We can't actually use the symbol names because kallsyms includes static symbols that are not exported from their object files.
[...]scripts/kallsyms.c static void write_src(void) · line 284
Quoted 9 lines
scripts/kallsyms.c +6
-1output_label ("kallsyms_addresses" );for (i =0 ; i < table_cnt; i++) { -printf ("\tPTR\t%#llx\n" , table[i].addr); +if (toupper (table[i].sym[0 ]) !='A' ) { +printf ("\tPTR\t_text + %#llx\n" , + table[i].addr - _text); + }else { +printf ("\tPTR\t%#llx\n" , table[i].addr); + }Doesn't this break kallsyms for almost everyone?
Quoted 4 lines
kallsyms addresses aren't used just for displaying, but also to find symbols from their addresses (from the stack trace, etc.).
Am I missing something?
Yes, you are missing something. This fixes the addresses in the table.
All this does is to put the same values in kallsyms that we have now
but it creates relocations for them. So on a kernel where we process
relocations before loading (because we are running the kernel at a different virtual address). The processing of the relocations will fix kallsyms to match the running kernel.
If we don't do this we will have the problems you are worried about.
Of course I would be overjoyed if you could point out a bug like you are worried about so I could fix it :)
Eric
PATCH 9/33 i386 boot: Add serial output support to the decompressor
In reply to Eric W. BiedermanThis patch does two very simple things.
It adds a serial output capability to the decompressor. It adds a command line parser for the early_printk option so we know which output method to use for the decompressor.
This makes debugging the decompressor a little easier, and keeps us from assuming we always have a vga console on all hardware.
--- arch/i386/boot/compressed/misc.c | 258 +++++++++++++++++++++++++++++++++++--- 1 files changed, 241 insertions(+), 17 deletions(-)
arch/i386/boot/compressed/misc.c +241 -17
@@ -9,11 +9,14 @@* High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 */ +#define __init#include <linux/config.h> #include <linux/linkage.h> #include <linux/vmalloc.h> +#include <linux/serial_reg.h> #include <linux/screen_info.h> #include <asm/io.h> +#include <asm/setup.h> /* * gzip declarations
@@ -24,7 +27,9 @@ #define STATIC static#undef memset#undef memcpy +#undef memcmp#define memzero (s, n) memset ((s), 0, (n)) +char *strstr (const char *haystack,const char *needle);typedef unsigned char uch ;typedef unsigned short ush ;
@@ -78,12 +83,17 @@ static void gzip_release(void **);* This is set up by the setup-routine at boot-time */ static unsigned char *real_mode;/* Pointer to real-mode data */ +static char saved_command_line[COMMAND_LINE_SIZE ];#define RM_EXT_MEM_K (*(unsigned short *)(real_mode + 0x2))#ifndef STANDARD_MEMORY_BIOS_CALL #define RM_ALT_MEM_K (*(unsigned long *)(real_mode + 0x1e0))#endif #define RM_SCREEN_INFO (*(struct screen_info *)(real_mode+0)) +#define RM_NEW_CL_POINTER ((char *)(unsigned long)(*(unsigned *)(real_mode+0x228))) +#define RM_OLD_CL_MAGIC (*(unsigned short *)(real_mode + 0x20)) +#define RM_OLD_CL_OFFSET (*(unsigned short *)(real_mode + 0x22)) +#define OLD_CL_MAGIC 0xA33Fextern unsigned char input_data[];extern int input_len;
@@ -97,8 +107,10 @@ static void free(void *where);static void *memset (void *s,int c,unsigned n);static void *memcpy (void *dest,const void *src,unsigned n); +static int memcmp (const void *s1,const void *s2,unsigned n);static void putstr (const char *); +static unsigned simple_strtou (const char *cp,char **endp,unsigned base);extern int end;static long free_mem_ptr = (long )&end;
@@ -112,14 +124,25 @@ static unsigned int low_buffer_end, low_static int high_loaded =0 ;static uch *high_buffer_start/* = (uch *)(((ulg)&end) + HEAP_SIZE)*/ ; -static char *vidmem = (char *)0xb8000 ; +static char *vidmem;static int vidport;static int lines, cols;#ifdef CONFIG_X86_NUMAQ -static void * xquad_portio =NULL ; +static void * xquad_portio;#endif +/* The early serial console */ + +#define DEFAULT_BAUD 9600 +#define DEFAULT_BASE 0x3f8/* ttyS0 */ +static unsigned serial_base =DEFAULT_BASE ; + +#define CONSOLE_NOOP 0 +#define CONSOLE_VID 1 +#define CONSOLE_SERIAL 2 +static int console =CONSOLE_NOOP ; +#include "../../../../lib/inflate.c" static void *malloc (int size)
@@ -154,7 +177,8 @@ static void gzip_release(void **ptr) free_mem_ptr = (long ) *ptr; } -static void scroll (void ) +/* The early video console */ +static void vid_scroll (void ) {int i;
@@ -163,7 +187,7 @@ static void scroll(void) vidmem[i] =' ' ; } -static void putstr (const char *s) +static void vid_putstr (const char *s) {int x,y,pos;char c;
@@ -175,7 +199,7 @@ static void putstr(const char *s)if ( c =='\n' ) { x =0 ;if ( ++y >= lines ) { -scroll (); +vid_scroll (); y--; } }else {
@@ -183,7 +207,7 @@ static void putstr(const char *s)if ( ++x >= cols ) { x =0 ;if ( ++y >= lines ) { -scroll (); +vid_scroll (); y--; } }
@@ -200,6 +224,178 @@ static void putstr(const char *s)outb_p (0xff & (pos >>1 ), vidport+1 ); } +static void vid_console_init (void ) +{ +if (RM_SCREEN_INFO .orig_video_mode ==7 ) { + vidmem = (char *)0xb0000 ; + vidport =0x3b4 ; + }else { + vidmem = (char *)0xb8000 ; + vidport =0x3d4 ; + } + + lines =RM_SCREEN_INFO .orig_video_lines; + cols =RM_SCREEN_INFO .orig_video_cols; +} + +/* The early serial console */ +static void serial_putc (int ch) +{ +if (ch =='\n' ) { +serial_putc ('\r' ); + } +/* Wait until I can send a byte */ +while ((inb (serial_base +UART_LSR ) &UART_LSR_THRE ) ==0 ) + ; + +/* Send the byte */ +outb (ch, serial_base +UART_TX ); + +/* Wait until the byte is transmitted */ +while (!(inb (serial_base +UART_LSR ) &UART_LSR_TEMT )) + ; +} + +static void serial_putstr (const char *str) +{ +int ch; +while ((ch = *str++) !='\0' ) { +if (ch =='\n' ) { +serial_putc ('\r' ); + } +serial_putc (ch); + } +} + +static void serial_console_init (char *s) +{ +unsigned base =DEFAULT_BASE ; +unsigned baud =DEFAULT_BAUD ; +unsigned divisor; +char *e; + +if (*s ==',' ) + ++s; +if (*s && (*s !=' ' )) { +if (memcmp (s,"0x" ,2 ) ==0 ) { + base =simple_strtou (s, &e,16 ); + }else { +static const unsigned bases[] = {0x3f8 ,0x2f8 }; +unsigned port; + +if (memcmp (s,"ttyS" ,4 ) ==0 ) + s +=4 ; + port =simple_strtou (s, &e,10 ); +if ((port >1 ) || (s == e)) + port =0 ; + base = bases[port]; + } + s = e; +if (*s ==',' ) + ++s; + } +if (*s && (*s !=' ' )) { + baud =simple_strtou (s, &e,0 ); +if ((baud ==0 ) || (s == e)) + baud =DEFAULT_BAUD ; + } + divisor =115200 / baud; + serial_base = base; + +outb (0x00 , serial_base +UART_IER );/* no interrupt */ +outb (0x00 , serial_base +UART_FCR );/* no fifo */ +outb (0x03 , serial_base +UART_MCR );/* DTR + RTS */ + +/* Set Baud Rate divisor */ +outb (0x83 , serial_base +UART_LCR ); +outb (divisor &0xff , serial_base +UART_DLL ); +outb (divisor >>8 , serial_base +UART_DLM ); +outb (0x03 , serial_base +UART_LCR );/* 8n1 */ + +} + +static void putstr (const char *str) +{ +if (console ==CONSOLE_VID ) { +vid_putstr (str); + }else if (console ==CONSOLE_SERIAL ) { +serial_putstr (str); + } +} + +static void console_init (char *cmdline) +{ + cmdline =strstr (cmdline,"earlyprintk=" ); +if (!cmdline) +return ; + cmdline +=12 ; +if (memcmp (cmdline,"vga" ,3 ) ==0 ) { +vid_console_init (); + console =CONSOLE_VID ; + }else if (memcmp (cmdline,"serial" ,6 ) ==0 ) { +serial_console_init (cmdline +6 ); + console =CONSOLE_SERIAL ; + }else if (memcmp (cmdline,"ttyS" ,4 ) ==0 ) { +serial_console_init (cmdline); + console =CONSOLE_SERIAL ; + } +} + +static inline int tolower (int ch) +{ +return ch |0x20 ; +} + +static inline int isdigit (int ch) +{ +return (ch >='0' ) && (ch <='9' ); +} + +static inline int isxdigit (int ch) +{ + ch =tolower (ch); +return isdigit (ch) || ((ch >='a' ) && (ch <='f' )); +} + + +static inline int digval (int ch) +{ +return isdigit (ch)? (ch -'0' ) :tolower (ch) -'a' +10 ; +} + +/** +* simple_strtou - convert a string to an unsigned +* @cp: The start of the string +* @endp: A pointer to the end of the parsed string will be placed here +* @base: The number base to use +*/ +static unsigned simple_strtou (const char *cp,char **endp,unsigned base) +{ +unsigned result =0 ,value; + +if (!base) { + base =10 ; +if (*cp =='0' ) { + base =8 ; + cp++; +if ((tolower (*cp) =='x' ) &&isxdigit (cp[1 ])) { + cp++; + base =16 ; + } + } + }else if (base ==16 ) { +if (cp[0 ] =='0' &&tolower (cp[1 ]) =='x' ) + cp +=2 ; + } +while (isxdigit (*cp) && ((value =digval (*cp)) < base)) { + result = result*base + value; + cp++; + } +if (endp) + *endp = (char *)cp; +return result; +} +static void *memset (void * s,int c,unsigned n) {int i;
@@ -218,6 +414,29 @@ static void* memcpy(void* dest, const voreturn dest; } +static int memcmp (const void *s1,const void *s2,unsigned n) +{ +const unsigned char *str1 = s1, *str2 = s2; +size_t i; +int result =0 ; +for (i =0 ; (result ==0 ) && (i < n); i++) { + result = *str1++ - *str2++; + } +return result; +} + +char *strstr (const char *haystack,const char *needle) +{ +size_t len; + len =strlen (needle); +while (*haystack) { +if (memcmp (haystack, needle, len) ==0 ) +return (char *)haystack; + haystack++; + } +return NULL ; +} +/* =========================================================================== * Fill the input buffer. This is called only when the buffer is empty * and at least one byte is really needed.
@@ -346,20 +565,25 @@ static void close_output_buffer_if_we_ru } } -asmlinkage int decompress_kernel(struct moveparams *mv, void *rmode) +static void save_command_line (void ) { - real_mode = rmode; - -if (RM_SCREEN_INFO .orig_video_mode ==7 ) { - vidmem = (char *)0xb0000 ; - vidport =0x3b4 ; - }else { - vidmem = (char *)0xb8000 ; - vidport =0x3d4 ; +/* Find the command line */ +char *cmdline; + cmdline = saved_command_line; +if (RM_NEW_CL_POINTER ) { + cmdline =RM_NEW_CL_POINTER ; + }else if (OLD_CL_MAGIC ==RM_OLD_CL_MAGIC ) { + cmdline = real_mode +RM_OLD_CL_OFFSET ; } +memcpy (saved_command_line, cmdline,COMMAND_LINE_SIZE ); + saved_command_line[COMMAND_LINE_SIZE -1 ] ='\0' ; +} - lines =RM_SCREEN_INFO .orig_video_lines; - cols =RM_SCREEN_INFO .orig_video_cols; +asmlinkage int decompress_kernel(struct moveparams *mv, void *rmode) +{ + real_mode = rmode; +save_command_line (); +console_init (saved_command_line);if (free_mem_ptr <0x100000 )setup_normal_output_buffer ();else setup_output_buffer_if_we_run_high (mv);
Signature · 1 line
1.4.2.rc2.g5209e
Re: [PATCH 9/33] i386 boot: Add serial output support to the decompressor
arch/i386/boot/compressed/misc.c static void putstr(const char *s) · line 227
Quoted 6 lines · Eric W. Biederman
arch/i386/boot/compressed/misc.c +1
-0}@@ -200,6 +224,178 @@ static void putstr(const char *s)outb_p (0xff & (pos >>1 ), vidport+1 ); } +static void vid_console_init (void )
Please just use early_printk instead of reimplementing this. I think it should work in this context too.
Quoted 5 lines
arch/i386/boot/compressed/misc.c +5
-0+static inline int tolower (int ch) +{ +return ch |0x20 ; +} +
arch/i386/boot/compressed/misc.c static void putstr(const char *s) · line 358
Quoted 10 lines
arch/i386/boot/compressed/misc.c +10
-0+static inline int isdigit (int ch) +{ +return (ch >='0' ) && (ch <='9' ); +} + +static inline int isxdigit (int ch) +{ + ch =tolower (ch); +return isdigit (ch) || ((ch >='a' ) && (ch <='f' )); +}
And please reuse the Linux code here.
Actually the best way to reuse would be to first do 64bit uncompressor and linker directly, but short of that #includes would be fine too.
Quoted 29 lines
arch/i386/boot/compressed/misc.c +29
-0+ + +static inline int digval (int ch) +{ +return isdigit (ch)? (ch -'0' ) :tolower (ch) -'a' +10 ; +} + +/** +* simple_strtou - convert a string to an unsigned +* @cp: The start of the string +* @endp: A pointer to the end of the parsed string will be placed here +* @base: The number base to use +*/ +static unsigned simple_strtou (const char *cp,char **endp,unsigned base) +{ +unsigned result =0 ,value; + +if (!base) { + base =10 ; +if (*cp =='0' ) { + base =8 ; + cp++; +if ((tolower (*cp) =='x' ) &&isxdigit (cp[1 ])) { + cp++; + base =16 ; + } + } + }else if (base ==16 ) { +if (cp[0 ] =='0' &&tolower (cp[1 ]) =='x' )
arch/i386/boot/compressed/misc.c static void putstr(const char *s) · line 397
Quoted 10 lines
arch/i386/boot/compressed/misc.c +10
-0+ cp +=2 ; + } +while (isxdigit (*cp) && ((value =digval (*cp)) < base)) { + result = result*base + value; + cp++; + } +if (endp) + *endp = (char *)cp; +return result; +}
Can you please somehow reuse the Linux one?
Quoted 19 lines
arch/i386/boot/compressed/misc.c +12
-0+static void *memset (void * s,int c,unsigned n) {int i;@@ -218,6 +414,29 @@ static void* memcpy(void* dest, const voreturn dest; } +static int memcmp (const void *s1,const void *s2,unsigned n) +{ +const unsigned char *str1 = s1, *str2 = s2; +size_t i; +int result =0 ; +for (i =0 ; (result ==0 ) && (i < n); i++) { + result = *str1++ - *str2++; + } +return result; +} +
arch/i386/boot/compressed/misc.c static void* memcpy(void* dest, const vo · line 437
Quoted 10 lines
arch/i386/boot/compressed/misc.c +10
-0+char *strstr (const char *haystack,const char *needle) +{ +size_t len; + len =strlen (needle); +while (*haystack) { +if (memcmp (haystack, needle, len) ==0 ) +return (char *)haystack; + haystack++; + } +return NULL ;
Would be better to just pull in lib/string.c
-Andi
Re: [PATCH 9/33] i386 boot: Add serial output support to the decompressor
Quoted 10 lines · Andi Kleen
arch/i386/boot/compressed/misc.c static void putstr(const char *s) · line 227
Quoted 6 lines · Eric W. Biederman
arch/i386/boot/compressed/misc.c +1
-0}@@ -200,6 +224,178 @@ static void putstr(const char *s)outb_p (0xff & (pos >>1 ), vidport+1 ); } +static void vid_console_init (void )Please just use
early_printkinstead of reimplementing this. I think it should work in this context too.
It doesn't or at least it didn't. I can look again though.
Quoted 9 lines
Quoted 9 lines
arch/i386/boot/compressed/misc.c +9
-0+static inline int tolower (int ch) +{ +return ch |0x20 ; +} + +static inline int isdigit (int ch) +{ +return (ch >='0' ) && (ch <='9' ); +}
Quoted 8 lines
arch/i386/boot/compressed/misc.c static void putstr(const char *s) · line 358
Quoted 6 lines
arch/i386/boot/compressed/misc.c +6
-0+ +static inline int isxdigit (int ch) +{ + ch =tolower (ch); +return isdigit (ch) || ((ch >='a' ) && (ch <='f' )); +}And please reuse the Linux code here.
Reuse is hard because we really are a separate executable, in a slightly different environment.
Quoted 4 lines
Actually the best way to reuse would be to first do 64bit uncompressor and linker directly, but short of that #includes would be fine too.
Would be better to just pull in
lib/string.c
Maybe. Size is fairly important here so I am concerned that I will pull in more than I need. But look and see if I can pull in just a subset of what is needed.
Eric
Re: [PATCH 9/33] i386 boot: Add serial output support to the decompressor
Quoted 7 lines
Quoted 5 lines
Actually the best way to reuse would be to first do 64bit uncompressor and linker directly, but short of that #includes would be fine too.
Would be better to just pull in
lib/string.cMaybe. Size is fairly important
Why is size important here?
-Andi
Re: [PATCH 9/33] i386 boot: Add serial output support to the decompressor
Quoted 8 lines · Andi Kleen
Quoted 6 lines
Quoted 4 lines
Actually the best way to reuse would be to first do 64bit uncompressor and linker directly, but short of that #includes would be fine too.
Would be better to just pull in
lib/string.cMaybe. Size is fairly important
Why is size important here?
For the same reason that we compress the kernel. ;)
This is the one chunk of code that we don't compress so every extra byte makes our executable bigger. Now I think the code size is actually in the 32k - 64k range so as long as it is a minor change it doesn't really matter.
The big pain with using lib/string.c and arch/x86_64/kernel/early_printk.c is that it is significant change in how the code of misc.c is constructed. Which means some serious reevaluation of all kinds of things need to be considered. Making it a lot of work :)
One of the practical dangers is that we make it more likely we can kill the boot by messing up the shared code.
I'm not certain what to think when even including normal kernel headers causes problems. It certainly makes me leery of including normal kernel code. But it might simplify some of the problems too.
Whichever way I go scrutinizing that possibility carefully is a lot of work.
Eric
Re: [PATCH 9/33] i386 boot: Add serial output support to the decompressor
Quoted 9 lines · Eric W. Biederman
Quoted 7 lines · Andi Kleen
Quoted 6 lines
Quoted 4 lines
Actually the best way to reuse would be to first do 64bit uncompressor and linker directly, but short of that #includes would be fine too.
Would be better to just pull in
lib/string.cMaybe. Size is fairly important
Quoted 8 lines
Quoted 1 line
Why is size important here?
For the same reason that we compress the kernel. ;)
This is the one chunk of code that we don't compress so every extra byte makes our executable bigger. Now I think the code size is actually in the 32k - 64k range so as long as it is a minor change it doesn't really matter.
text data bss dec hex filename 1909 352 12 2273 8e1 arch/x86_64/kernel/early_printk.o 2212 0 0 2212 8a4 lib/string.o
It's minor.
Quoted 4 lines
The big pain with using
lib/string.candarch/x86_64/kernel/early_printk.cis that it is significant change in how the code ofmisc.cis constructed.
Not if you use #include
Quoted 6 lines
Which means some
serious reevaluation of all kinds of things need to be considered. Making it a lot of work :)One of the practical dangers is that we make it more likely we can kill the boot by messing up the shared code.
If they're messed up the later boot will fail too. Doesn't make too much difference.
Quoted 5 lines
I'm not certain what to think when even including normal kernel headers causes problems. It certainly makes me leery of including normal kernel code. But it might simplify some of the problems too.
On x86-64 some trouble comes from it being 32bit code. That is why I suggested making it 64bit first, which would avoid many of the problems.
Quoted 2 lines
Whichever way I go scrutinizing that possibility carefully is a lot of work.
64bit conversion would be some work, the rest isn't I think.
Alternatively if you don't like it we can just drop these compressor patches. I don't think they were essential.
-Andi
Re: [PATCH 9/33] i386 boot: Add serial output support to the decompressor
Quoted 5 lines · Andi Kleen
On Wednesday 02 August 2006 06:57, Eric W. Biederman wrote:
On x86-64 some trouble comes from it being 32bit code. That is why I suggested making it 64bit first, which would avoid many of the problems.
:)
Quoted 4 lines
Quoted 2 lines
Whichever way I go scrutinizing that possibility carefully is a lot of work.
64bit conversion would be some work, the rest isn't I think.
Except for the head.S work the 64bit conversion was practically a noop.
Quoted 2 lines
Alternatively if you don't like it we can just drop these compressor patches. I don't think they were essential.
Agreed. The printing portion wasn't essential.
At this point I think dropping the non-essential bits just to get the size of the patchset down makes sense.
Eric
Re: [PATCH 9/33] i386 boot: Add serial output support to the decompressor
In reply to Andi KleenQuoted 10 lines · Andi Kleen
arch/i386/boot/compressed/misc.c static void putstr(const char *s) · line 227
Quoted 6 lines · Eric W. Biederman
arch/i386/boot/compressed/misc.c +1
-0}@@ -200,6 +224,178 @@ static void putstr(const char *s)outb_p (0xff & (pos >>1 ), vidport+1 ); } +static void vid_console_init (void )Please just use
early_printkinstead of reimplementing this. I think it should work in this context too.
There is certainly some value in that. To do that I would need to refactor early_printk to make it useable.
This comment from one of patches summaries the worst of the problems.
Quoted 5 lines
/* WARNING!!
* This code is compiled with -fPIC and it is relocated dynamically
* at run time, but no relocation processing is performed.
* This means that it is not safe to place pointers in static structures. */
lib/string.c might be useful. The fact that the functions are not static slightly concerns me. I have a vague memory of non-static functions generating relocations for no good reason.
Eric
Re: [PATCH 9/33] i386 boot: Add serial output support to the decompressor
Quoted 6 lines
Quoted 6 lines
/* WARNING!!
* This code is compiled with -fPIC and it is relocated dynamically
* at run time, but no relocation processing is performed.
* This means that it is not safe to place pointers in static structures. */
iirc the only static relocation in early_printk is the one to initialize the console pointers - that could certainly be moved to be at run time.
Quoted 3 lines
lib/string.cmight be useful. The fact that the functions are not static slightly concerns me. I have a vague memory of non-static functions generating relocations for no good reason.
Would surprise me.
-Andi
Re: [PATCH 9/33] i386 boot: Add serial output support to the decompressor
Quoted 9 lines · Andi Kleen
Quoted 5 lines
Quoted 5 lines
/* WARNING!!
* This code is compiled with -fPIC and it is relocated dynamically
* at run time, but no relocation processing is performed.
* This means that it is not safe to place pointers in static structures. */iirc the only static relocation in
early_printkis the one to initialize the console pointers - that could certainly be moved to be at run time.
The function pointers in the console structure are also a problem.
static struct console simnow_console = {
.name = "simnow",
.write = simnow_write,
.flags = CON_PRINTBUFFER,
.index = -1,
};Quoted 5 lines
Quoted 3 lines
lib/string.cmight be useful. The fact that the functions are not static slightly concerns me. I have a vague memory of non-static functions generating relocations for no good reason.Would surprise me.
The context where it bit me was memtest86, if I recall correctly. The problem there was I did process relocations and I discovered simply by making functions static or at least non-exported I had many fewer relocations to process.
Since I am relying on a very clever trick to generate code that doesn't have relocations at run time I have to be careful.
So if I want to continue not processing relocations. I need to be careful not to use constructs that will generate a procedure linkage table, which I think only kicks in with external functions and multiple files.
I need to be careful not to put pointers in statically allocated data structures.
Ideally the code would be setup so you can compile out consoles the user finds uninteresting.
It is annoying to have to call strlen on all of the strings you want to print..
So there are plenty of mismatches, there.
But we may be able to harmonized them, and reuse early_printk.
Eric
Re: [PATCH 9/33] i386 boot: Add serial output support to the decompressor
Quoted 8 lines
The function pointers in the console structure are also a problem.
static struct console simnow_console = { .name = "simnow", .write = simnow_write, .flags = CON_PRINTBUFFER, .index = -1, };
Yes just patch them at runtime.
Quoted 2 lines
Ideally the code would be setup so you can compile out consoles the user finds uninteresting.
Seems overkill for early_printk
Quoted 2 lines
It is annoying to have to call strlen on all of the strings you want to print..
What strlen?
-Andi
Re: [PATCH 9/33] i386 boot: Add serial output support to the decompressor
Quoted 10 lines · Andi Kleen
Quoted 8 lines
The function pointers in the console structure are also a problem.
static struct console simnow_console = { .name = "simnow", .write = simnow_write, .flags = CON_PRINTBUFFER, .index = -1, };Yes just patch them at runtime.
I guess that can work. It's a bit of a pain though.
Quoted 4 lines
Quoted 2 lines
Ideally the code would be setup so you can compile out consoles the user finds uninteresting.
Seems overkill for
early_printk
At least compiling completely out probably isn't.
I have had too many times where the size of a bzImage was an important factor on a project.
Quoted 4 lines
Quoted 2 lines
It is annoying to have to call strlen on all of the strings you want to print..
What strlen?
The strlen that is needed to convert putstr(char *s) into the write method for the early_printk helpers.
Eric
PATCH 10/33 i386: Relocatable kernel support.
In reply to Eric W. BiedermanThis patch modifies the x86 kernel so that if CONFIG_RELOCATABLE is selected it will be able to be loaded at any 4K aligned address below 1G. The technique used is to compile the decompressor with -fPIC and modify it so the decompressor is fully relocatable. For the main kernel relocations are generated. Resulting in a kernel that is relocatable with no runtime overhead and no need to modify the source code.
A reserved 32bit word in the parameters has been assigned to serve as a stack so we figure out where are running.
--- arch/i386/Kconfig | 12 + arch/i386/Makefile | 2 arch/i386/boot/compressed/Makefile | 22 + arch/i386/boot/compressed/head.S | 184 +++++++---- arch/i386/boot/compressed/misc.c | 263 ++++++++------- arch/i386/boot/compressed/relocs.c | 563 +++++++++++++++++++++++++++++++++ arch/i386/boot/compressed/vmlinux.lds | 40 ++ arch/i386/boot/compressed/vmlinux.scr | 3 arch/i386/boot/setup.S | 29 +- include/linux/screen_info.h | 3 10 files changed, 910 insertions(+), 211 deletions(-)
arch/i386/Kconfig +12 -0
@@ -761,6 +761,18 @@ config CRASH_DUMP help Generate crash dump after being started by kexec. +config RELOCATABLE + bool "Build a relocatable kernel" + help + This build a kernel image that retains relocation information + so it can be loaded someplace besides the default 1MB. + The relocations tend to the kernel binary about 10% larger, + but are discarded at runtime. + + One use is for the kexec on panic case where the recovery kernel + must live at a different physical address than the primary + kernel. + config PHYSICAL_START hex "Physical address where the kernel is loaded" if (EMBEDDED || CRASH_DUMP)
arch/i386/Makefile +1 -1
@@ -26,7 +26,7 @@ endif LDFLAGS := -m elf_i386 OBJCOPYFLAGS := -O binary -R .note -R .comment -S -LDFLAGS_vmlinux := +LDFLAGS_vmlinux := --emit-relocs CHECKFLAGS += -D__i386__ CFLAGS += -pipe -msoft-float
arch/i386/boot/compressed/Makefile +18 -4
@@ -7,19 +7,33 @@ # targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o EXTRA_AFLAGS := -traditional -LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32 +LDFLAGS_vmlinux := -T +CFLAGS_misc.o += -fPIC +hostprogs-y := relocs -$(obj)/vmlinux: $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE +$(obj)/vmlinux: $(src)/vmlinux.lds $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE $(call if_changed,ld) @: $(obj)/vmlinux.bin: vmlinux FORCE $(call if_changed,objcopy) -$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE +quiet_cmd_relocs = RELOCS $@ + cmd_relocs = $(obj)/relocs $< > $@ +$(obj)/vmlinux.relocs: vmlinux $(obj)/relocs FORCE + $(call if_changed,relocs) + +vmlinux.bin.all-y := $(obj)/vmlinux.bin +vmlinux.bin.all-$(CONFIG_RELOCATABLE) += $(obj)/vmlinux.relocs +quiet_cmd_relocbin = BUILD $@ + cmd_relocbin = cat $(filter-out FORCE,$^) > $@ +$(obj)/vmlinux.bin.all: $(vmlinux.bin.all-y) FORCE + $(call if_changed,relocbin) + +$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin.all FORCE $(call if_changed,gzip) LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T -$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE +$(obj)/piggy.o: $(src)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE $(call if_changed,ld)
arch/i386/boot/compressed/head.S +117 -67
219 lines not on this page · raw message
arch/i386/boot/compressed/misc.c +134 -129
338 lines not on this page · raw message
arch/i386/boot/compressed/relocs.c new file +563 -0
563 lines not on this page · raw message
arch/i386/boot/compressed/vmlinux.lds new file +40 -0
@@ -0,0 +1,40 @@ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(startup_32) +SECTIONS +{ + . = 0 ; + .text.head : { + _head = . ; + *(.text.head) + _ehead = . ; + } + .data.compressed : { + *(.data.compressed) + } + .text : { + _text = .; /* Text */ + *(.text) + *(.text.*) + _etext = . ; + } + .rodata : { + _rodata = . ; + *(.rodata) /* read-only data */ + *(.rodata.*) + _erodata = . ; + } + .data : { + _data = . ; + *(.data) + *(.data.*) + _edata = . ; + } + .bss : { + _bss = . ; + *(.bss) + *(.bss.*) + *(COMMON) + _end = . ; + } +}
arch/i386/boot/compressed/vmlinux.scr +2 -1
@@ -1,9 +1,10 @@ SECTIONS { - .data : { + .data.compressed : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) + output_len = . - 4; input_data_end = .; } }
arch/i386/boot/setup.S +21 -8
@@ -588,11 +588,6 @@ rmodeswtch_normal: call default_switch rmodeswtch_end: -# we get the code32 start address and modify the below 'jmpi' -# (loader may have changed it) - movl %cs:code32_start, %eax - movl %eax, %cs:code32 - # Now we move the system to its rightful place ... but we check if we have a # big-kernel. In that case we *must* not move it ... testb $LOADED_HIGH, %cs:loadflags
@@ -788,11 +783,12 @@ a20_err_msg: a20_done: #endif /* CONFIG_X86_VOYAGER */ -# set up gdt and idt +# set up gdt and idt and 32bit start address lidt idt_48 # load idt with 0,0 xorl %eax, %eax # Compute gdt_base movw %ds, %ax # (Convert %ds:gdt to a linear ptr) shll $4, %eax + addl %eax, code32 addl $gdt, %eax movl %eax, (gdt_48+2) lgdt gdt_48 # load gdt with whatever is
@@ -851,9 +847,26 @@ # take our 48 bit far pointer. (INTeL 80 # Manual, Mixing 16-bit and 32-bit code, page 16-6) .byte 0x66, 0xea # prefix + jmpi-opcode -code32: .long 0x1000 # will be set to 0x100000 - # for big kernels +code32: .long startup_32 # will be set to %cs+startup_32 .word __BOOT_CS +.code32 +startup_32: + movl $(__BOOT_DS), %eax + movl %eax, %ds + movl %eax, %es + movl %eax, %fs + movl %eax, %gs + movl %eax, %ss + + xorl %eax, %eax +1: incl %eax # check that A20 really IS enabled + movl %eax, 0x00000000 # loop forever if it isn't + cmpl %eax, 0x00100000 + je 1b + + # Jump to the 32bit entry point + jmpl *(code32_start - start + (DELTA_INITSEG << 4))(%esi) +.code16 # Here's a bunch of information about your current kernel.. kernel_version: .ascii UTS_RELEASE
include/linux/screen_info.h +2 -1
@@ -42,7 +42,8 @@ struct screen_info {u16 pages;/* 0x32 */ u16 vesa_attributes;/* 0x34 */ u32 capabilities;/* 0x36 */ -/* 0x3a -- 0x3f reserved for future expansion */ +/* 0x3a -- 0x3b reserved for future expansion */ +/* 0x3c -- 0x3f micro stack for relocatable kernels */ };extern struct screen_info screen_info;
Signature · 1 line
1.4.2.rc2.g5209e
Re: [PATCH 10/33] i386: Relocatable kernel support.
Quoted 4 lines
arch/i386/boot/compressed/vmlinux.scr +0
-0@@ -1,9 +1,10 @@ SECTIONS
arch/i386/boot/compressed/vmlinux.scr line 10
Quoted 10 lines
arch/i386/boot/compressed/vmlinux.scr +2
-1{ - .data : { + .data.compressed : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) + output_len = . - 4; input_data_end = .; } }
I don't see how you are getting the uncompressed length from output_len...
--Mika
Re: [PATCH 10/33] i386: Relocatable kernel support.
Quoted 11 lines · Mika Penttilä
arch/i386/boot/compressed/vmlinux.scr line 8
Quoted 10 lines
arch/i386/boot/compressed/vmlinux.scr +1
-1@@ -1,9 +1,10 @@ SECTIONS { - .data : { + .data.compressed : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) + output_len = . - 4; input_data_end = .; } }I don't see how you are getting the uncompressed length from
output_len...
It's part of the gzip format. It places the length at the end of the compressed data. I am just computing the address of where gzip put the length and putting a variable there called output_len.
Isn't linker script magic wonderful :)
Eric
Re: [PATCH 10/33] i386: Relocatable kernel support.
Quoted 14 lines · Eric W. Biederman
Quoted 11 lines · Mika Penttil?
arch/i386/boot/compressed/vmlinux.scr line 8
Quoted 10 lines
arch/i386/boot/compressed/vmlinux.scr +1
-1@@ -1,9 +1,10 @@ SECTIONS { - .data : { + .data.compressed : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) + output_len = . - 4; input_data_end = .; } }I don't see how you are getting the uncompressed length from
output_len...
Quoted 5 lines
It's part of the gzip format. It places the length at the end of the compressed data. I am just computing the address of where gzip put the length and putting a variable there called
output_len.Isn't linker script magic wonderful :)
A comment would be appreciated.
Sam
Re: [PATCH 10/33] i386: Relocatable kernel support.
In reply to Eric W. BiedermanQuoted 17 lines · Eric W. Biederman
Quoted 4 lines · Mika Penttilä
Quoted 4 lines
arch/i386/boot/compressed/vmlinux.scr +0
-1@@ -1,9 +1,10 @@ SECTIONS { - .data : { + .data.compressed : {Quoted 9 lines
Review line 9
Quoted 7 lines
(quoted diff) +1
-0input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) + output_len = . - 4; input_data_end = .; } }I don't see how you are getting the uncompressed length from
output_len...
Quoted 9 lines
It's part of the gzip format. It places the length at the end of the compressed data. I am just computing the address of where gzip put the length and putting a variable there called
output_len.Isn't linker script magic wonderful :)
Eric
-
Huh, quite a nice trick indeed!
Thanks,
Mika
PATCH 11/33 i386 boot: Add an ELF header to bzImage
In reply to Eric W. BiedermanIncreasingly the cobbled together boot protocol that is bzImage does not have the flexibility to deal with booting in new situations.
Now that we no longer support the bootsector loader we have 512 bytes at the very start of a bzImage that we can use for other things.
Placing an ELF header there allows us to retain a single binary for all of x86 while at the same time describing things that bzImage does not allow us to describe.
The existing bugger off code for warning if we attempt to boot from the bootsector is kept but the error message is made more terse so we have a little more room to play with.
--- arch/i386/boot/Makefile | 2 arch/i386/boot/bootsect.S | 97 ++++++++++++++++++- arch/i386/boot/tools/build.c | 214 +++++++++++++++++++++++++++++++++++++----- include/linux/elf_boot.h | 19 ++++ 4 files changed, 303 insertions(+), 29 deletions(-)
arch/i386/boot/Makefile +1 -1
@@ -43,7 +43,7 @@ # -------------------------------------- quiet_cmd_image = BUILD $@ cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/bootsect $(obj)/setup \ - $(obj)/vmlinux.bin $(ROOT_DEV) > $@ + $(obj)/vmlinux.bin $(ROOT_DEV) vmlinux > $@ $(obj)/zImage $(obj)/bzImage: $(obj)/bootsect $(obj)/setup \ $(obj)/vmlinux.bin $(obj)/tools/build FORCE
arch/i386/boot/bootsect.S +93 -4
120 lines not on this page · raw message
arch/i386/boot/tools/build.c +190 -24
269 lines not on this page · raw message
include/linux/elf_boot.h new file +19 -0
@@ -0,0 +1,19 @@ +#ifndef ELF_BOOT_H +#define ELF_BOOT_H + +/* Elf notes to help bootloaders identify what program they are booting. +*/ + +/* Standardized Elf image notes for booting... The name for all of these is ELFBoot */ +#define ELF_NOTE_BOOT "ELFBoot" + +#define EIN_PROGRAM_NAME 0x00000001 +/* The program in this ELF file */ +#define EIN_PROGRAM_VERSION 0x00000002 +/* The version of the program in this ELF file */ +#define EIN_PROGRAM_CHECKSUM 0x00000003 +/* ip style checksum of the memory image. */ +#define EIN_ARGUMENT_STYLE 0x00000004 +/* String identifying argument passing style */ + +#endif /* ELF_BOOT_H */
Signature · 1 line
1.4.2.rc2.g5209e
Re: [PATCH 11/33] i386 boot: Add an ELF header to bzImage
Quoted 4 lines · Eric W. Biederman
+.macro note name, type
arch/i386/boot/bootsect.S +2
-0+ .balign 4 + .int 2f - 1f # n_namesz
arch/i386/boot/bootsect.S #endif · line 123
Quoted 10 lines
arch/i386/boot/bootsect.S +10
-0+ .int 4f - 3f # n_descsz + .int \type # n_type + .balign 4 +1: .asciz "\name" +2: .balign 4 +3: +.endm +.macro enote +4: .balign 4 +.endm
This is very similar to the macro I introduced in the Paravirt note segment patch. Do think they should be made common?
include/linux/elf_boot.h line 8
Quoted 6 lines
include/linux/elf_boot.h new file +5
-0+/* Elf notes to help bootloaders identify what program they are booting. +*/ + +/* Standardized Elf image notes for booting... The name for all of these is ELFBoot */ +#define ELF_NOTE_BOOT "ELFBoot"
I wonder if this should be something to suggest its Linux-specific? Or do you see this being used by a wider audience?
J
Re: [PATCH 11/33] i386 boot: Add an ELF header to bzImage
Quoted 10 lines · Jeremy Fitzhardinge
Quoted 9 lines · Eric W. Biederman
+.macro note name, type
arch/i386/boot/bootsect.S +8
-0+ .balign 4 + .int 2f - 1f # n_namesz + .int 4f - 3f # n_descsz + .int \type # n_type + .balign 4 +1: .asciz "\name" +2: .balign 4 +3:
Quoted 8 lines
Quoted 5 lines
+.endm
+.macro enote
+4: .balign 4
+.endmThis is very similar to the macro I introduced in the Paravirt note segment patch. Do think they should be made common?
Yes. At the point of merging these two approaches I think the notes should just be put into vmlinux and copied either into the ELF header or more likely into a segment that build.c tacks onto the kernel.
It is such a small piece of my overall picture I wasn't really looking at that.
Quoted 10 lines
include/linux/elf_boot.h
Quoted 4 lines
include/linux/elf_boot.h new file +4
-0+/* Elf notes to help bootloaders identify what program they are booting. +*/ + +/* Standardized Elf image notes for booting... The name for all of these is ELFBoot */
Quoted 2 lines
+#define
ELF_NOTE_BOOT"ELFBoot"I wonder if this should be something to suggest its Linux-specific? Or do you see this being used by a wider audience?
This note is used in etherboot and LinuxBIOS right now so it isn't terribly linux specific. And whatever the virtues of it's name it is actually in use.
I had a preliminary RFC for using these in a winder context at one point but I ran out of energy for pushing it.
I think the information in those note headers is interesting beyond that I really don't much care.
Eric
PATCH 12/33 x86_64: fixup indentation in e820.c
In reply to Eric W. Biederman--- arch/x86_64/kernel/e820.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
arch/x86_64/kernel/e820.c +2 -2
@@ -205,8 +205,8 @@ unsigned long __init e820_end_of_ram(voiif (start >= end)continue ;if (ei->type ==E820_RAM ) { -if (end > end_pfn<<PAGE_SHIFT ) - end_pfn = end>>PAGE_SHIFT ; +if (end > end_pfn<<PAGE_SHIFT ) + end_pfn = end>>PAGE_SHIFT ; }else {if (end > end_pfn_map<<PAGE_SHIFT ) end_pfn_map = end>>PAGE_SHIFT ;
Signature · 1 line
1.4.2.rc2.g5209e
PATCH 13/33 x86_64: Remove assumptions about the kernel start address from e820/bad_addr()
In reply to Eric W. Biederman--- arch/x86_64/kernel/e820.c | 9 +++++++-- 1 files changed, 7 insertions(+), 2 deletions(-)
arch/x86_64/kernel/e820.c +7 -2
@@ -69,9 +69,14 @@ #ifdef CONFIG_BLK_DEV_INITRD return 1; }#endif -/* kernel code + 640k memory hole (later should not be needed, but +/* 640k memory hole (later should not be needed, but be paranoid for now) */ -if (last >=640 *1024 && addr <__pa_symbol (&_end)) { +if (last >=640 *1024 && addr <HIGH_MEMORY ) { + *addrp =HIGH_MEMORY ; + } + +/* kernel code */ +if (last >=__pa_symbol (&_text) && addr <__pa_symbol (&_end)) { *addrp =__pa_symbol (&_end);return 1 ; }
Signature · 1 line
1.4.2.rc2.g5209e
PATCH 14/33 x86_64: Properly report in /proc/iomem the kernel address
In reply to Eric W. BiedermanThe code assumed that the kernel was always loaded at 1M in memory. This fixes that assumption.
--- arch/x86_64/kernel/setup.c | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-)
arch/x86_64/kernel/setup.c +3 -2
@@ -521,7 +521,7 @@ static void discover_ebda(void)void __init setup_arch (char **cmdline_p) { -unsigned long kernel_end; +unsigned long kernel_start, kernel_end;ROOT_DEV =old_decode_dev (ORIG_ROOT_DEV ); screen_info =SCREEN_INFO ;
@@ -596,8 +596,9 @@ #endif (table_end - table_start) << PAGE_SHIFT);/* reserve kernel */ + kernel_start =__pa_symbol (&_text); kernel_end =round_up (__pa_symbol (&_end),PAGE_SIZE ); -reserve_bootmem_generic (HIGH_MEMORY , kernel_end -HIGH_MEMORY ); +reserve_bootmem_generic (kernel_start, kernel_end - kernel_start);/* * reserve physical page 0 - it's a special BIOS page on many boxes,
Signature · 1 line
1.4.2.rc2.g5209e
PATCH 15/33 x86_64: Fix kernel direct mapping size check
In reply to Eric W. BiedermanInstead of using physical addresse of _end which has nothing to do with knowing if the kernel fits within it's reserved virtual addresses, verify the virtual address of _end fits within in the kernel virtual address mapping.
--- arch/x86_64/kernel/head64.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
arch/x86_64/kernel/head64.c +1 -1
@@ -116,7 +116,7 @@ #ifdef CONFIG_X86_IO_APIC disable_apic =1 ;#endif /* You need early console to see that */ -if (__pa_symbol (&_end) >=KERNEL_TEXT_SIZE ) +if (((unsigned long )&_end) >= (__START_KERNEL_map +KERNEL_TEXT_SIZE ))panic ("Kernel too big for kernel mapping\n" );setup_boot_cpu_data ();
Signature · 1 line
1.4.2.rc2.g5209e
PATCH 16/33 x86_64: Assembly safe page.h and pgtable.h
In reply to Eric W. BiedermanThis patch makes pgtable.h and page.h safe to include in assembly files like head.S. Allowing us to use symbolic constants instead of hard coded numbers when refering to the page tables.
This patch copies asm-sparc64/const.h to asm-x86_64 to get a definition of _AC() a very convinient macro that allows us to force the type when we are compiling the code in C and to drop all of the type information when we are using the constant in assembly. Previously this was done with multiple definition of the same constant. const.h was modified slightly so that it works when given CONFIG options as arguments.
This patch adds #ifndef __ASSEMBLY__ ... #endif and _AC(1,UL) where appropriate so the assembler won't choke on the header files. Otherwise nothing should have changed.
--- include/asm-x86_64/const.h | 20 ++++++++++++++++++++ include/asm-x86_64/page.h | 34 +++++++++++++--------------------- include/asm-x86_64/pgtable.h | 33 +++++++++++++++++++++------------ 3 files changed, 54 insertions(+), 33 deletions(-)
include/asm-x86_64/const.h new file +20 -0
@@ -0,0 +1,20 @@ +/* const.h: Macros for dealing with constants. */ + +#ifndef _X86_64_CONST_H +#define _X86_64_CONST_H + +/* Some constant macros are used in both assembler and +* C code. Therefore we cannot annotate them always with +* 'UL' and other type specificers unilaterally. We +* use the following macros to deal with this. +*/ + +#ifdef __ASSEMBLY__ +#define _AC (X ,Y ) X +#else +#define __AC (X ,Y ) (X##Y) +#define _AC (X ,Y ) __AC(X,Y) +#endif + + +#endif /* !(_X86_64_CONST_H) */
include/asm-x86_64/page.h +13 -21
@@ -1,14 +1,11 @@#ifndef _X86_64_PAGE_H#define _X86_64_PAGE_H +#include <asm/const.h> /* PAGE_SHIFT determines the page size */ #define PAGE_SHIFT 12 -#ifdef __ASSEMBLY__ -#define PAGE_SIZE (0x1 << PAGE_SHIFT) -#else -#define PAGE_SIZE (1UL << PAGE_SHIFT) -#endif +#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT)#define PAGE_MASK (~(PAGE_SIZE-1))#define PHYSICAL_PAGE_MASK (~(PAGE_SIZE-1) & __PHYSICAL_MASK)
@@ -33,10 +30,10 @@ #define MCE_STACK 5#define N_EXCEPTION_STACKS 5/* hw limit: 7 */ #define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1)) -#define LARGE_PAGE_SIZE (1UL << PMD_SHIFT) +#define LARGE_PAGE_SIZE (_AC(1,UL) << PMD_SHIFT)#define HPAGE_SHIFT PMD_SHIFT -#define HPAGE_SIZE ((1UL) << HPAGE_SHIFT) +#define HPAGE_SIZE (_AC(1,UL) << HPAGE_SHIFT)#define HPAGE_MASK (~(HPAGE_SIZE - 1))#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
@@ -76,29 +73,24 @@ #define __pud(x) ((pud_t) { (x) } )#define __pgd (x) ((pgd_t) { (x) } )#define __pgprot (x) ((pgprot_t) { (x) } ) -#define __PHYSICAL_START ((unsigned long)CONFIG_PHYSICAL_START) -#define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START) -#define __START_KERNEL_map 0xffffffff80000000UL -#define __PAGE_OFFSET 0xffff810000000000UL +#endif /* !__ASSEMBLY__ */ -#else -#define __PHYSICAL_START CONFIG_PHYSICAL_START +#define __PHYSICAL_START _AC(CONFIG_PHYSICAL_START,UL)#define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START) -#define __START_KERNEL_map 0xffffffff80000000 -#define __PAGE_OFFSET 0xffff810000000000 -#endif /* !__ASSEMBLY__ */ +#define __START_KERNEL_map _AC(0xffffffff80000000,UL) +#define __PAGE_OFFSET _AC(0xffff810000000000,UL)/* to align the pointer to the (next) page boundary */ #define PAGE_ALIGN (addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)/* See Documentation/x86_64/mm.txt for a description of the memory map. */ #define __PHYSICAL_MASK_SHIFT 46 -#define __PHYSICAL_MASK ((1UL << __PHYSICAL_MASK_SHIFT) - 1) +#define __PHYSICAL_MASK ((_AC(1,UL) << __PHYSICAL_MASK_SHIFT) - 1)#define __VIRTUAL_MASK_SHIFT 48 -#define __VIRTUAL_MASK ((1UL << __VIRTUAL_MASK_SHIFT) - 1) +#define __VIRTUAL_MASK ((_AC(1,UL) << __VIRTUAL_MASK_SHIFT) - 1) -#define KERNEL_TEXT_SIZE (40UL*1024*1024) -#define KERNEL_TEXT_START 0xffffffff80000000UL +#define KERNEL_TEXT_SIZE (_AC(40,UL)*1024*1024) +#define KERNEL_TEXT_START _AC(0xffffffff80000000,UL)#ifndef __ASSEMBLY__
@@ -106,7 +98,7 @@ #include <asm/bug.h>#endif /* __ASSEMBLY__ */ -#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET) +#define PAGE_OFFSET __PAGE_OFFSET/* Note: __pa(&symbol_visible_to_c) should be always replaced with __pa_symbol. Otherwise you risk miscompilation. */
include/asm-x86_64/pgtable.h +21 -12
@@ -1,6 +1,9 @@#ifndef _X86_64_PGTABLE_H#define _X86_64_PGTABLE_H +#include <asm/const.h> +#ifndef __ASSEMBLY__ +/* * This file contains the functions and defines necessary to modify and use * the x86-64 page table tree.
@@ -34,6 +37,8 @@ extern unsigned long pgkern_mask;extern unsigned long empty_zero_page[PAGE_SIZE /sizeof (unsigned long )];#define ZERO_PAGE (vaddr) (virt_to_page(empty_zero_page)) +#endif /* !__ASSEMBLY__ */ +/* * PGDIR_SHIFT determines what a top-level page table entry can map */
@@ -58,6 +63,8 @@ #define PTRS_PER_PMD 512*/ #define PTRS_PER_PTE 512 +#ifndef __ASSEMBLY__ +#define pte_ERROR (e) \ printk("%s:%d: bad pte %p(%016lx).\n", __FILE__, __LINE__, &(e), pte_val(e))#define pmd_ERROR (e) \
@@ -124,22 +131,23 @@ #define pte_same(a, b) ((a).pte == (b).#define pte_pgprot (a) (__pgprot((a).pte & ~PHYSICAL_PAGE_MASK)) -#define PMD_SIZE (1UL << PMD_SHIFT) +#endif /* !__ASSEMBLY__ */ + +#define PMD_SIZE (_AC(1,UL) << PMD_SHIFT)#define PMD_MASK (~(PMD_SIZE-1)) -#define PUD_SIZE (1UL << PUD_SHIFT) +#define PUD_SIZE (_AC(1,UL) << PUD_SHIFT)#define PUD_MASK (~(PUD_SIZE-1)) -#define PGDIR_SIZE (1UL << PGDIR_SHIFT) +#define PGDIR_SIZE (_AC(1,UL) << PGDIR_SHIFT)#define PGDIR_MASK (~(PGDIR_SIZE-1))#define USER_PTRS_PER_PGD ((TASK_SIZE-1)/PGDIR_SIZE+1)#define FIRST_USER_ADDRESS 0 -#ifndef __ASSEMBLY__ -#define MAXMEM 0x3fffffffffffUL -#define VMALLOC_START 0xffffc20000000000UL -#define VMALLOC_END 0xffffe1ffffffffffUL -#define MODULES_VADDR 0xffffffff88000000UL -#define MODULES_END 0xfffffffffff00000UL +#define MAXMEM _AC(0x3fffffffffff,UL) +#define VMALLOC_START _AC(0xffffc20000000000,UL) +#define VMALLOC_END _AC(0xffffe1ffffffffff,UL) +#define MODULES_VADDR _AC(0xffffffff88000000,UL) +#define MODULES_END _AC(0xfffffffffff00000,UL)#define MODULES_LEN (MODULES_END - MODULES_VADDR)#define _PAGE_BIT_PRESENT 0
@@ -165,7 +173,7 @@ #define _PAGE_FILE 0x040 /* nonlinear fi#define _PAGE_GLOBAL 0x100/* Global TLB entry */ #define _PAGE_PROTNONE 0x080/* If not present */ -#define _PAGE_NX (1UL<<_PAGE_BIT_NX) +#define _PAGE_NX (_AC(1,UL)<<_PAGE_BIT_NX)#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
@@ -227,6 +235,8 @@ #define __S101 PAGE_READONLY_EXEC#define __S110 PAGE_SHARED_EXEC#define __S111 PAGE_SHARED_EXEC +#ifndef __ASSEMBLY__ +static inline unsigned long pgd_bad (pgd_t pgd) {unsigned long val =pgd_val (pgd);
@@ -418,8 +428,6 @@ extern spinlock_t pgd_lock;extern struct page *pgd_list;void vmalloc_sync_all (void ); -#endif /* !__ASSEMBLY__ */ -extern int kern_addr_valid (unsigned long addr);#define io_remap_pfn_range (vma, vaddr, pfn, size, prot) \
@@ -449,5 +457,6 @@ #define __HAVE_ARCH_PTEP_GET_AND_CLEAR_F#define __HAVE_ARCH_PTEP_SET_WRPROTECT#define __HAVE_ARCH_PTE_SAME#include <asm-generic/pgtable.h> +#endif /* !__ASSEMBLY__ */ #endif /* _X86_64_PGTABLE_H */
Signature · 1 line
1.4.2.rc2.g5209e
PATCH 17/33 x86_64: Separate normal memory map initialization from the hotplug case
In reply to Eric W. BiedermanCurrently initializing the two memory maps are combining into one set of functions with if(after_bootmem) tests scattered all over to handle the semantic differences. Just trying to think about what is supposed to happen when and why makes my head hurt.
In one case we initialize a page but in another we don't because it has been zeroed by the allocator.
In one case we have to map and unmap pages and in another we don't because we have a mapping of the pages already.
In one case we care if a page table is partially initialized and in the other we don't.
It is ugly to reason through and makes maintenance difficult, because the rules are different in the two cases. So I have separated these code paths so the can evolve separately. I think code duplication is the lesser of two evils here.
--- arch/x86_64/mm/init.c | 147 +++++++++++++++++++++++++++++++++---------------- 1 files changed, 98 insertions(+), 49 deletions(-)
arch/x86_64/mm/init.c +98 -49
@@ -179,19 +179,13 @@ static struct temp_map { {} }; -static __meminit void *alloc_low_page (int *index,unsigned long *phys) +static __init void *alloc_low_page (int *index,unsigned long *phys) {struct temp_map *ti;int i;unsigned long pfn = table_end++, paddr;void *adr; -if (after_bootmem) { - adr = (void *)get_zeroed_page (GFP_ATOMIC ); - *phys =__pa (adr); -return adr; - } -if (pfn >= end_pfn)panic ("alloc_low_page: ran out of memory" );for (i =0 ; temp_mappings[i].allocated; i++) {
@@ -210,13 +204,10 @@ static __meminit void *alloc_low_page(inreturn adr; } -static __meminit void unmap_low_page (int i) +static __init void unmap_low_page (int i) {struct temp_map *ti; -if (after_bootmem) -return ; - ti = &temp_mappings[i];set_pmd (ti->pmd,__pmd (0 )); ti->allocated =0 ;
@@ -249,7 +240,7 @@ __init void early_iounmap(void *addr, un__flush_tlb (); } -static void __meminit +static void __init phys_pmd_init (pmd_t *pmd,unsigned long address,unsigned long end) {int i;
@@ -258,9 +249,8 @@ phys_pmd_init(pmd_t *pmd, unsigned longunsigned long entry;if (address >= end) { -if (!after_bootmem) -for (; i <PTRS_PER_PMD ; i++, pmd++) -set_pmd (pmd,__pmd (0 )); +for (; i <PTRS_PER_PMD ; i++, pmd++) +set_pmd (pmd,__pmd (0 ));break ; } entry = _PAGE_NX|_PAGE_PSE|_KERNPG_TABLE|_PAGE_GLOBAL|address;
@@ -269,30 +259,12 @@ phys_pmd_init(pmd_t *pmd, unsigned long } } -static void __meminit -phys_pmd_update (pud_t *pud,unsigned long address,unsigned long end) -{ -pmd_t *pmd =pmd_offset (pud, (unsigned long )__va (address)); - -if (pmd_none (*pmd)) { -spin_lock (&init_mm.page_table_lock); -phys_pmd_init (pmd, address, end); -spin_unlock (&init_mm.page_table_lock); -__flush_tlb_all (); - } -} - -static void __meminit phys_pud_init (pud_t *pud,unsigned long address,unsigned long end) +static void __init phys_pud_init (pud_t *pud,unsigned long address,unsigned long end) {long i =pud_index (address); pud = pud + i; -if (after_bootmem &&pud_val (*pud)) { -phys_pmd_update (pud, address, end); -return ; - } -for (; i <PTRS_PER_PUD ; pud++, i++) {int map;unsigned long paddr, pmd_phys;
@@ -302,16 +274,14 @@ static void __meminit phys_pud_init(pud_if (paddr >= end)break ; -if (!after_bootmem && !e820_any_mapped (paddr, paddr+PUD_SIZE ,0 )) { +if (!e820_any_mapped (paddr, paddr+PUD_SIZE ,0 )) {set_pud (pud,__pud (0 ));continue ; } pmd =alloc_low_page (&map, &pmd_phys); -spin_lock (&init_mm.page_table_lock);set_pud (pud,__pud (pmd_phys | _KERNPG_TABLE));phys_pmd_init (pmd, paddr, end); -spin_unlock (&init_mm.page_table_lock);unmap_low_page (map); }__flush_tlb ();
@@ -345,7 +315,7 @@ static void __init find_early_table_spac/* Setup the direct mapping of the physical memory at PAGE_OFFSET. This runs before bootmem is initialized and gets pages directly from the physical memory. To access them they are temporarily mapped. */ -void __meminit init_memory_mapping (unsigned long start,unsigned long end) +void __init init_memory_mapping (unsigned long start,unsigned long end) {unsigned long next;
@@ -357,8 +327,7 @@ void __meminit init_memory_mapping(unsig* mapped. Unfortunately this is done currently before the nodes are * discovered. */ -if (!after_bootmem) -find_early_table_space (end); +find_early_table_space (end); start = (unsigned long )__va (start); end = (unsigned long )__va (end);
@@ -369,22 +338,17 @@ void __meminit init_memory_mapping(unsigpgd_t *pgd =pgd_offset_k (start);pud_t *pud; -if (after_bootmem) - pud =pud_offset (pgd, start &PGDIR_MASK ); -else - pud =alloc_low_page (&map, &pud_phys); + pud =alloc_low_page (&map, &pud_phys); next = start +PGDIR_SIZE ;if (next > end) next = end;phys_pud_init (pud,__pa (start),__pa (next)); -if (!after_bootmem) -set_pgd (pgd_offset_k (start),mk_kernel_pgd (pud_phys)); +set_pgd (pgd_offset_k (start),mk_kernel_pgd (pud_phys));unmap_low_page (map); } -if (!after_bootmem) - asmvolatile ("movq %%cr4,%0" :"=r" (mmu_cr4_features)); + asmvolatile ("movq %%cr4,%0" :"=r" (mmu_cr4_features));__flush_tlb_all (); }
@@ -529,6 +493,91 @@ int memory_add_physaddr_to_nid(u64 start }#endif +static void +late_phys_pmd_init (pmd_t *pmd,unsigned long address,unsigned long end) +{ +int i; + +for (i =0 ; i <PTRS_PER_PMD ; pmd++, i++, address +=PMD_SIZE ) { +unsigned long entry; + +if (address >= end) +break ; + entry = _PAGE_NX|_PAGE_PSE|_KERNPG_TABLE|_PAGE_GLOBAL|address; + entry &= __supported_pte_mask; +set_pmd (pmd,__pmd (entry)); + } +} + +static void +late_phys_pmd_update (pud_t *pud,unsigned long address,unsigned long end) +{ +pmd_t *pmd =pmd_offset (pud, (unsigned long )__va (address)); + +if (pmd_none (*pmd)) { +spin_lock (&init_mm.page_table_lock); +late_phys_pmd_init (pmd, address, end); +spin_unlock (&init_mm.page_table_lock); +__flush_tlb_all (); + } +} + +static void late_phys_pud_init (pud_t *pud,unsigned long address,unsigned long end) +{ +long i =pud_index (address); + + pud = pud + i; + +if (pud_val (*pud)) { +late_phys_pmd_update (pud, address, end); +return ; + } + +for (; i <PTR_PER_PUD ; pud++, i++) { +unsigned long paddr, pmd_phys; +pmd_t *pmd; + + paddr = (address &PGDIR_MASK ) + i*PUD_SIZE ; +if (paddr >= end) +break ; + + pmd = (pmd_t *)get_zeroed_page (GFP_ATOMIC ); + phys_pmd =__pa (pmd); + +spin_lock (&init_mm.page_table_lock); +set_pud (pud,__pud (pmd_phys | _KERNPG_TABLE)); +late_phys_pmd_init (pmd, paddr, end); +spin_unlock (&init_mm.page_table_lock); + } +} + +/* Setup the direct mapping of the physical memory at PAGE_OFFSET. +* This runs after bootmem is initialized and gets pages normally. +*/ +static void late_init_memory_mapping (unsigned long start,unsigned long end) +{ +unsigned long next; + +Dprintk ("add_memory_mapping\n" ); + + start = (unsigned long )__va (start); + end = (unsigned long )__va (end); + +for (; start < end; start = next) { +unsigned long pud_phys; +pgd_t *pgd =pgd_offset_k (start); +pud_t *pud; + + pud =pud_offset (pgd, start &PGDIR_MASK ); + + next = start +PGDIR_SIZE ; +if (next > end) + next = end; +late_phys_pud_init (pud,__pa (start),__pa (next)); + } +__flush_tlb_all (); +} +/* * Memory is added always to NORMAL zone. This means you will never get * additional DMA/DMA32 memory.
@@ -545,7 +594,7 @@ int arch_add_memory(int nid, u64 start,if (ret) goto error; -init_memory_mapping (start, (start + size -1 )); +late_init_memory_mapping (start, (start + size -1 ));return ret; error:
Signature · 1 line
1.4.2.rc2.g5209e
PATCH 18/33 x86_64: Kill temp_boot_pmds
In reply to Eric W. BiedermanEarly in the boot process we need the ability to set up temporary mappings, before our normal mechanisms are initialized. Currently this is used to map pages that are part of the page tables we are building and pages during the dmi scan.
The core problem is that we are using the user portion of the page tables to implement this. Which means that while this mechanism is active we cannot catch NULL pointer dereferences and we deviate from the normal ways of handling things.
In this patch I modify early_ioremap to map pages into the kernel portion of address space, roughly where we will later put modules, and I make the discovery of which addresses we can use dynamic which removes all kinds of static limits and remove the dependencies on implementation details between different parts of the code.
I also modify the early page table initialization code to use early_ioreamp and early_iounmap, instead of the special case version of those functions that they are now calling.
The only really silly part left with init_memory_mapping is that find_early_table_space always finds pages below 1M.
--- arch/x86_64/kernel/head.S | 3 - arch/x86_64/mm/init.c | 104 ++++++++++++++++++--------------------------- 2 files changed, 42 insertions(+), 65 deletions(-)
arch/x86_64/kernel/head.S +0 -3
@@ -278,9 +278,6 @@ NEXT_PAGE(level2_ident_pgt) .quad i << 21 | 0x083 i = i + 1 .endr - /* Temporary mappings for the super early allocator in arch/x86_64/mm/init.c */ - .globl temp_boot_pmds -temp_boot_pmds: .fill 492,8,0 NEXT_PAGE(level2_kernel_pgt)
arch/x86_64/mm/init.c +42 -62
154 lines not on this page · raw message
Signature · 1 line
1.4.2.rc2.g5209e
Re: [PATCH 18/33] x86_64: Kill temp_boot_pmds
Quoted 5 lines · Eric W. Biederman
I also modify the early page table initialization code to use
early_ioreampandearly_iounmap, instead of the special case version of those functions that they are now calling.
Ok valuable cleanup. I queued that one too.
Quoted 2 lines
The only really silly part left with
init_memory_mappingis thatfind_early_table_spacealways finds pages below 1M.
I fixed this some time ago - obsolete comment?
-Andi
Re: [PATCH 18/33] x86_64: Kill temp_boot_pmds
Quoted 7 lines · Andi Kleen
Quoted 5 lines · Eric W. Biederman
I also modify the early page table initialization code to use
early_ioreampandearly_iounmap, instead of the special case version of those functions that they are now calling.
Quoted 6 lines
Ok valuable cleanup. I queued that one too.
Quoted 2 lines
The only really silly part left with
init_memory_mappingis thatfind_early_table_spacealways finds pages below 1M.I fixed this some time ago - obsolete comment?
Yes an obsolete comment. I thought I had rechecked that but I was skimming to fast. find_e820_memory certainly isn't limited to pages below 1M.
Eric
Re: [PATCH 18/33] x86_64: Kill temp_boot_pmds II
In reply to Eric W. BiedermanQuoted 5 lines · Eric W. Biederman
I also modify the early page table initialization code to use
early_ioreampandearly_iounmap, instead of the special case version of those functions that they are now calling.
Or rather I tried to apply it - it doesn't apply at all on its own:
patching file arch/x86_64/mm/init.c
Hunk #1 FAILED at 167.
Hunk #2 succeeded at 274 with fuzz 1 (offset 28 lines). Hunk #3 FAILED at 286.
Hunk #4 FAILED at 341.
3 out of 4 hunks FAILED -- rejects in file arch/x86_64/mm/init.c
-Andi
Re: [PATCH 18/33] x86_64: Kill temp_boot_pmds II
Quoted 10 lines · Andi Kleen
Quoted 5 lines · Eric W. Biederman
I also modify the early page table initialization code to use
early_ioreampandearly_iounmap, instead of the special case version of those functions that they are now calling.Or rather I tried to apply it - it doesn't apply at all on its own:
Quoted 6 lines
patching file
arch/x86_64/mm/init.c
Hunk #1 FAILED at 167.
Hunk #2 succeeded at 274 with fuzz 1 (offset 28 lines). Hunk #3 FAILED at 286.
Hunk #4 FAILED at 341.
3 out of 4 hunks FAILED -- rejects in filearch/x86_64/mm/init.c
It is probably patch 17:
"x86_64: Separate normal memory map initialization from the hotplug case"
I don't see any other patches that touch arch/x86_64/mm/init.c before that. At least not in 2.6.18-rc3, which is the base of my patchset.
Eric
Re: [PATCH 18/33] x86_64: Kill temp_boot_pmds II
Quoted 3 lines
It is probably patch 17:
"x86_64: Separate normal memory map initialization from the hotplug case"
Ok that messes things up. Actually I think i prefered the previous code - it was not that bad as you make it. The two variants. are really doing mostly the same. So best you drop that.
Quoted 3 lines
I don't see any other patches that touch
arch/x86_64/mm/init.cbefore that. At least not in 2.6.18-rc3, which is the base of my patchset.
I got three patches that touch mm/init.c in my patchkit (ftp://ftp.firstfloor.org/pub/ak/x86_64/quilt/patches/)
BTW I didn't merge any further patches currently, but might after the next round when the current comments are addressed.
-Andi
Re: [PATCH 18/33] x86_64: Kill temp_boot_pmds II
Quoted 6 lines · Andi Kleen
Quoted 2 lines
It is probably patch 17:
"x86_64: Separate normal memory map initialization from the hotplug case"Ok that messes things up. Actually I think i prefered the previous code - it was not that bad as you make it. The two variants. are really doing mostly the same. So best you drop that.
All of my complaints are real. But yes I do think a reasonable case can be made for merging them. In several of the worst cases simply calling memset before initializing the page is probably sufficient to remove a test later on.
As that code sits right now you need way too much global context to understand what is going on. It is the kind of code that cause obviously correct patches to fail, and I'm clever enough to know clever code is very dangerous. :)
So before I get back to that I will probably look and see if there is some more heavy lifting I can do to make that code less of a land mine.
Quoted 9 lines
Quoted 3 lines
I don't see any other patches that touch
arch/x86_64/mm/init.cbefore that. At least not in 2.6.18-rc3, which is the base of my patchset.I got three patches that touch
mm/init.cin my patchkit (ftp://ftp.firstfloor.org/pub/ak/x86_64/quilt/patches/)BTW I didn't merge any further patches currently, but might after the next round when the current comments are addressed.
Ok. I will take a look.
Having any patches merged on a simple request for comments was a bit of a surprise :)
Eric
PATCH 19/33 x86_64: Cleanup the early boot page table.
In reply to Eric W. Biederman- Merge physmem_pgt and ident_pgt, removing physmem_pgt. The merge is broken as soon as mm/init.c:init_memory_mapping is run.
- As physmem_pgt is gone don't export it in pgtable.h.
- Use defines from pgtable.h for page permissions.
- Fix the physical memory identity mapping so it is at the correct address.
- Remove the physical memory mapping from wakeup_level4_pgt it is at the wrong address so we can't possibly be usinging it.
- Simply NEXT_PAGE the work to calculate the phys_ alias of the labels was very cool. Unfortuantely it was a brittle special purpose hack that makes maitenance more difficult. Instead just use label - __START_KERNEL_map like we do everywhere else in assembly.
--- arch/x86_64/kernel/head.S | 61 +++++++++++++++++++----------------------- include/asm-x86_64/pgtable.h | 1 - 2 files changed, 28 insertions(+), 34 deletions(-)
arch/x86_64/kernel/head.S +28 -33
@@ -15,6 +15,7 @@ #include <linux/threads.h> #include <linux/init.h> #include <asm/desc.h> #include <asm/segment.h> +#include <asm/pgtable.h> #include <asm/page.h> #include <asm/msr.h> #include <asm/cache.h>
@@ -250,52 +251,48 @@ ljumpvector: ENTRY(stext) ENTRY(_stext) - $page = 0 #define NEXT_PAGE(name) \ - $page = $page + 1; \ - .org $page * 0x1000; \ - phys_/**/name = $page * 0x1000 + __PHYSICAL_START; \ + .balign PAGE_SIZE; \ ENTRY(name) +/* Automate the creation of 1 to 1 mapping pmd entries */ +#define PMDS(START, PERM, COUNT) \ + i = 0 ; \ + .rept (COUNT) ; \ + .quad (START) + (i << 21) + (PERM) ; \ + i = i + 1 ; \ + .endr + NEXT_PAGE(init_level4_pgt) /* This gets initialized in x86_64_start_kernel */ .fill 512,8,0 NEXT_PAGE(level3_ident_pgt) - .quad phys_level2_ident_pgt | 0x007 + .quad level2_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE .fill 511,8,0 NEXT_PAGE(level3_kernel_pgt) .fill 510,8,0 /* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */ - .quad phys_level2_kernel_pgt | 0x007 + .quad level2_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE .fill 1,8,0 NEXT_PAGE(level2_ident_pgt) - /* 40MB for bootup. */ - i = 0 - .rept 20 - .quad i << 21 | 0x083 - i = i + 1 - .endr - .fill 492,8,0 + /* Since I easily can, map the first 1G. + * Don't set NX because code runs from these pages. + */ + PMDS(0x0000000000000000, __PAGE_KERNEL_LARGE_EXEC, PTRS_PER_PMD) NEXT_PAGE(level2_kernel_pgt) /* 40MB kernel mapping. The kernel code cannot be bigger than that. When you change this change KERNEL_TEXT_SIZE in page.h too. */ /* (2^48-(2*1024*1024*1024)-((2^39)*511)-((2^30)*510)) = 0 */ - i = 0 - .rept 20 - .quad i << 21 | 0x183 - i = i + 1 - .endr + PMDS(0x0000000000000000, __PAGE_KERNEL_LARGE_EXEC|_PAGE_GLOBAL, + KERNEL_TEXT_SIZE/PMD_SIZE) /* Module mapping starts here */ - .fill 492,8,0 - -NEXT_PAGE(level3_physmem_pgt) - .quad phys_level2_kernel_pgt | 0x007 /* so that __va works even before pagetable_init */ - .fill 511,8,0 + .fill (PTRS_PER_PMD - (KERNEL_TEXT_SIZE/PMD_SIZE)),8,0 +#undef PMDS #undef NEXT_PAGE .data
@@ -303,12 +300,10 @@ #undef NEXT_PAGE #ifdef CONFIG_ACPI_SLEEP .align PAGE_SIZE ENTRY(wakeup_level4_pgt) - .quad phys_level3_ident_pgt | 0x007 - .fill 255,8,0 - .quad phys_level3_physmem_pgt | 0x007 - .fill 254,8,0 + .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE + .fill 510,8,0 /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */ - .quad phys_level3_kernel_pgt | 0x007 + .quad level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE #endif #ifndef CONFIG_HOTPLUG_CPU
@@ -322,12 +317,12 @@ #endif */ .align PAGE_SIZE ENTRY(boot_level4_pgt) - .quad phys_level3_ident_pgt | 0x007 - .fill 255,8,0 - .quad phys_level3_physmem_pgt | 0x007 - .fill 254,8,0 + .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE + .fill 257,8,0 + .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE + .fill 252,8,0 /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */ - .quad phys_level3_kernel_pgt | 0x007 + .quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE .data
include/asm-x86_64/pgtable.h +0 -1
@@ -15,7 +15,6 @@ #include <linux/threads.h>#include <asm/pda.h> extern pud_t level3_kernel_pgt[512 ]; -extern pud_t level3_physmem_pgt[512 ];extern pud_t level3_ident_pgt[512 ];extern pmd_t level2_kernel_pgt[512 ];extern pgd_t init_level4_pgt[];
Signature · 1 line
1.4.2.rc2.g5209e
PATCH 20/33 x86_64: fix early_printk to use the standard ISA mapping
In reply to Eric W. Biederman--- arch/x86_64/kernel/early_printk.c | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-)
arch/x86_64/kernel/early_printk.c +1 -2
@@ -11,11 +11,10 @@ #include <asm/fcntl.h>#ifdef __i386__#include <asm/setup.h> -#define VGABASE (__ISA_IO_base + 0xb8000)#else #include <asm/bootsetup.h> -#define VGABASE ((void __iomem *)0xffffffff800b8000UL)#endif +#define VGABASE (__ISA_IO_base + 0xb8000)static int max_ypos =25 , max_xpos =80 ;static int current_ypos =25 , current_xpos =0 ;
Signature · 1 line
1.4.2.rc2.g5209e
PATCH 21/33 x86_64: modify copy_bootdata to use virtual addresses
In reply to Eric W. BiedermanUse virtual addresses instead of physical addresses in copy bootdata. In addition fix the implementation of the old bootloader convention. Everything is at real_mode_data always. It is just that sometimes real_mode_data was relocated by setup.S to not sit at 0x90000.
--- arch/x86_64/kernel/head64.c | 17 ++++++++--------- 1 files changed, 8 insertions(+), 9 deletions(-)
arch/x86_64/kernel/head64.c +8 -9
@@ -29,29 +29,28 @@ static void __init clear_bss(void) }#define NEW_CL_POINTER 0x228/* Relative to real mode data */ -#define OLD_CL_MAGIC_ADDR 0x90020 +#define OLD_CL_MAGIC_ADDR 0x20#define OLD_CL_MAGIC 0xA33F -#define OLD_CL_BASE_ADDR 0x90000 -#define OLD_CL_OFFSET 0x90022 +#define OLD_CL_OFFSET 0x22extern char saved_command_line[];static void __init copy_bootdata (char *real_mode_data) { -int new_data; +unsigned long new_data;char * command_line;memcpy (x86_boot_params, real_mode_data,BOOT_PARAM_SIZE ); - new_data = *(int *) (x86_boot_params +NEW_CL_POINTER ); + new_data = *(u32 *) (x86_boot_params +NEW_CL_POINTER );if (!new_data) { -if (OLD_CL_MAGIC != * (u16 *)OLD_CL_MAGIC_ADDR ) { +if (OLD_CL_MAGIC != *(u16 *)(real_mode_data +OLD_CL_MAGIC_ADDR )) {printk ("so old bootloader that it does not support commandline?!\n" );return ; } - new_data =OLD_CL_BASE_ADDR + * (u16 *)OLD_CL_OFFSET ; + new_data =__pa (real_mode_data) + *(u16 *)(real_mode_data +OLD_CL_OFFSET );printk ("old bootloader convention, maybe loadlin?\n" ); } - command_line = (char *) ((u64)(new_data)); + command_line =__va (new_data);memcpy (saved_command_line, command_line,COMMAND_LINE_SIZE );printk ("Bootdata ok (command line is %s)\n" , saved_command_line); }
@@ -99,7 +98,7 @@ void __init x86_64_start_kernel(char * rcpu_pda (i) = &boot_cpu_pda[i];pda_init (0 ); -copy_bootdata (real_mode_data); +copy_bootdata (__va (real_mode_data));#ifdef CONFIG_SMP cpu_set (0 , cpu_online_map);#endif
Signature · 1 line
1.4.2.rc2.g5209e
PATCH 22/33 x86_64: Fix gdt table size in trampoline.S
In reply to Eric W. Biederman--- arch/x86_64/kernel/trampoline.S | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
arch/x86_64/kernel/trampoline.S +1 -1
@@ -64,7 +64,7 @@ idt_48: .word 0, 0 # idt base = 0L gdt_48: - .short __KERNEL32_CS + 7 # gdt limit + .short GDT_ENTRIES*8 - 1 # gdt limit .long cpu_gdt_table-__START_KERNEL_map .globl trampoline_end
Signature · 1 line
1.4.2.rc2.g5209e
Re: [PATCH 22/33] x86_64: Fix gdt table size in trampoline.S
Makes sense, thanks. I queued the patch.
-Andi
PATCH 23/33 x86_64: cleanup segments
In reply to Eric W. BiedermanMove __KERNEL32_CS up into the unused gdt entry. __KERNEL32_CS is used when entering the kernel so putting it first is useful when trying to keep boot gdt sizes to a minimum.
Set the accessed bit on all gdt entries. We don't care so there is no need for the cpu to burn the extra cycles, and it potentially allows the pages to be immutable. Plus it is confusing when debugging and your gdt entries mysteriously change.
--- arch/x86_64/kernel/head.S | 14 +++++++------- include/asm-x86_64/segment.h | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-)
arch/x86_64/kernel/head.S +7 -7
@@ -352,16 +352,16 @@ #endif ENTRY(cpu_gdt_table) .quad 0x0000000000000000 /* NULL descriptor */ + .quad 0x00cf9b000000ffff /* __KERNEL32_CS */ + .quad 0x00af9b000000ffff /* __KERNEL_CS */ + .quad 0x00cf93000000ffff /* __KERNEL_DS */ + .quad 0x00cffb000000ffff /* __USER32_CS */ + .quad 0x00cff3000000ffff /* __USER_DS, __USER32_DS */ + .quad 0x00affb000000ffff /* __USER_CS */ .quad 0x0 /* unused */ - .quad 0x00af9a000000ffff /* __KERNEL_CS */ - .quad 0x00cf92000000ffff /* __KERNEL_DS */ - .quad 0x00cffa000000ffff /* __USER32_CS */ - .quad 0x00cff2000000ffff /* __USER_DS, __USER32_DS */ - .quad 0x00affa000000ffff /* __USER_CS */ - .quad 0x00cf9a000000ffff /* __KERNEL32_CS */ .quad 0,0 /* TSS */ .quad 0,0 /* LDT */ - .quad 0,0,0 /* three TLS descriptors */ + .quad 0,0,0 /* three TLS descriptors */ .quad 0 /* unused */ gdt_end: /* asm/segment.h:GDT_ENTRIES must match this */
include/asm-x86_64/segment.h +2 -2
@@ -6,7 +6,7 @@ #include <asm/cache.h>#define __KERNEL_CS 0x10#define __KERNEL_DS 0x18 -#define __KERNEL32_CS 0x38 +#define __KERNEL32_CS 0x08/* * we cannot use the same code segment descriptor for user and kernel
@@ -20,7 +20,7 @@ #define __USER_DS 0x2b /* 5*8+3 */#define __USER_CS 0x33/* 6*8+3 */ #define __USER32_DS __USER_DS -#define GDT_ENTRY_TLS 1 +#define GDT_ENTRY_TLS 7#define GDT_ENTRY_TSS 8/* needs two entries */ #define GDT_ENTRY_LDT 10/* needs two entries */ #define GDT_ENTRY_TLS_MIN 12
Signature · 1 line
1.4.2.rc2.g5209e
PATCH 24/33 x86_64: Add EFER to the set registers saved by save_processor_state
In reply to Eric W. BiedermanEFER varies like %cr4 depending on the cpu capabilities, and which cpu capabilities we want to make use of. So save/restore it make certain we have the same EFER value when we are done.
--- arch/x86_64/kernel/suspend.c | 3 ++- include/asm-x86_64/suspend.h | 1 + 2 files changed, 3 insertions(+), 1 deletions(-)
arch/x86_64/kernel/suspend.c +2 -1
@@ -33,7 +33,6 @@ void __save_processor_state(struct saved asmvolatile ("str %0" :"=m" (ctxt->tr));/* XMM0..XMM15 should be handled by kernel_fpu_begin(). */ -/* EFER should be constant for kernel version, no need to handle it. */ /* * segment registers */
@@ -50,6 +49,7 @@ void __save_processor_state(struct saved/* * control registers */ +rdmsrl (MSR_EFER , ctxt->efer); asmvolatile ("movq %%cr0, %0" :"=r" (ctxt->cr0)); asmvolatile ("movq %%cr2, %0" :"=r" (ctxt->cr2)); asmvolatile ("movq %%cr3, %0" :"=r" (ctxt->cr3));
@@ -75,6 +75,7 @@ void __restore_processor_state(struct sa/* * control registers */ +wrmsrl (MSR_EFER , ctxt->efer); asmvolatile ("movq %0, %%cr8" ::"r" (ctxt->cr8)); asmvolatile ("movq %0, %%cr4" ::"r" (ctxt->cr4)); asmvolatile ("movq %0, %%cr3" ::"r" (ctxt->cr3));
include/asm-x86_64/suspend.h +1 -0
@@ -17,6 +17,7 @@ struct saved_context {u16 ds, es, fs, gs, ss;unsigned long gs_base, gs_kernel_base, fs_base;unsigned long cr0, cr2, cr3, cr4, cr8; +unsigned long efer;u16 gdt_pad;u16 gdt_limit;unsigned long gdt_base;
Signature · 1 line
1.4.2.rc2.g5209e
PATCH 25/33 x86_64: 64bit PIC SMP trampoline
In reply to Eric W. BiedermanThis modifies the SMP trampoline and all of the associated code so it can jump to a 64bit kernel loaded at an arbitrary address.
The dependencies on having an idenetity mapped page in the kernel page tables for SMP bootup have all been removed.
In addition the trampoline has been modified to verify that long mode is supported. Asking if long mode is implemented is down right silly but we have traditionally had some of these checks, and they can't hurt anything. So when the totally ludicrous happens we just might handle it correctly.
--- arch/x86_64/kernel/head.S | 1 arch/x86_64/kernel/setup.c | 9 -- arch/x86_64/kernel/trampoline.S | 168 ++++++++++++++++++++++++++++++++++++--- 3 files changed, 156 insertions(+), 22 deletions(-)
arch/x86_64/kernel/head.S +1 -0
@@ -103,6 +103,7 @@ startup_32: .org 0x100 .globl startup_64 startup_64: +ENTRY(secondary_startup_64) /* We come here either from startup_32 * or directly from a 64bit bootloader. * Since we may have come directly from a bootloader we
arch/x86_64/kernel/setup.c +1 -8
@@ -611,15 +611,8 @@ #endifreserve_bootmem_generic (ebda_addr, ebda_size);#ifdef CONFIG_SMP -/* -* But first pinch a few for the stack/trampoline stuff -* FIXME: Don't need the extra page at 4K, but need to fix -* trampoline before removing it. (see the GDT stuff) -*/ -reserve_bootmem_generic (PAGE_SIZE ,PAGE_SIZE ); -/* Reserve SMP trampoline */ -reserve_bootmem_generic (SMP_TRAMPOLINE_BASE ,PAGE_SIZE ); +reserve_bootmem_generic (SMP_TRAMPOLINE_BASE ,2 *PAGE_SIZE );#endif #ifdef CONFIG_ACPI_SLEEP
arch/x86_64/kernel/trampoline.S +154 -14
213 lines not on this page · raw message
Signature · 1 line
1.4.2.rc2.g5209e
Re: [PATCH 25/33] x86_64: 64bit PIC SMP trampoline
arch/x86_64/kernel/trampoline.S r_base = . · line 86
Quoted 8 lines · Eric W. Biederman
arch/x86_64/kernel/trampoline.S +7
-1- ljmpl $__KERNEL32_CS, $(startup_32-__START_KERNEL_map) + + # flush prefetch and jump to startup_32 + ljmpl *(startup_32_vector - r_base) + + .code32 + .balign 4 +startup_32:
It would be nicer if you could factor out that code into a common file between head.S and trampoline.S
-Andi
PATCH 26/33 x86_64: 64bit PIC ACPI wakeup
In reply to Eric W. Biederman- Killed lots of dead code
- Improve the cpu sanity checks to verify long mode
is enabled when we wake up.
- Removed the need for modifying any existing kernel page table.
- Moved wakeup_level4_pgt into the wakeup routine so we can run the kernel above 4G.
- Increased the size of the wakeup routine to 8K.
- Renamed the variables to use the 64bit register names.
- Lots of misc cleanups to match trampoline.S
I don't have a configuration I can test this but it compiles cleanly and it should work, the code is very similar to the SMP trampoline, which I have tested. At least now the comments about still running in low memory are actually correct.
--- arch/x86_64/kernel/acpi/sleep.c | 19 -- arch/x86_64/kernel/acpi/wakeup.S | 325 +++++++++++++++++--------------------- arch/x86_64/kernel/head.S | 9 - include/asm-x86_64/suspend.h | 12 + 4 files changed, 151 insertions(+), 214 deletions(-)
arch/x86_64/kernel/acpi/sleep.c +2 -17
@@ -60,17 +60,6 @@ extern char wakeup_start, wakeup_end;extern unsigned long FASTCALL (acpi_copy_wakeup_routine (unsigned long )); -static pgd_t low_ptr; - -static void init_low_mapping (void ) -{ -pgd_t *slot0 =pgd_offset (current->mm,0UL ); - low_ptr = *slot0; -set_pgd (slot0, *pgd_offset (current->mm,PAGE_OFFSET )); -WARN_ON (num_online_cpus () !=1 ); -local_flush_tlb (); -} -/** * acpi_save_state_mem - save kernel state *
@@ -79,8 +68,6 @@ static void init_low_mapping(void)*/ int acpi_save_state_mem (void ) { -init_low_mapping (); -memcpy ((void *)acpi_wakeup_address, &wakeup_start, &wakeup_end - &wakeup_start);acpi_copy_wakeup_routine (acpi_wakeup_address);
@@ -93,8 +80,6 @@ int acpi_save_state_mem(void)*/ void acpi_restore_state_mem (void ) { -set_pgd (pgd_offset (current->mm,0UL ), low_ptr); -local_flush_tlb (); }/**
@@ -107,8 +92,8 @@ void acpi_restore_state_mem(void)*/ void __init acpi_reserve_bootmem (void ) { - acpi_wakeup_address = (unsigned long )alloc_bootmem_low (PAGE_SIZE ); -if ((&wakeup_end - &wakeup_start) >PAGE_SIZE ) + acpi_wakeup_address = (unsigned long )alloc_bootmem_low (PAGE_SIZE *2 ); +if ((&wakeup_end - &wakeup_start) > (PAGE_SIZE *2 ))printk (KERN_CRIT "ACPI: Wakeup code way too big, will crash on attempt to suspend\n" ); }
arch/x86_64/kernel/acpi/wakeup.S +143 -182
494 lines not on this page · raw message
arch/x86_64/kernel/head.S +0 -9
@@ -298,15 +298,6 @@ #undef NEXT_PAGE .data -#ifdef CONFIG_ACPI_SLEEP - .align PAGE_SIZE -ENTRY(wakeup_level4_pgt) - .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE - .fill 510,8,0 - /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */ - .quad level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE -#endif - #ifndef CONFIG_HOTPLUG_CPU __INITDATA #endif
include/asm-x86_64/suspend.h +6 -6
@@ -45,12 +45,12 @@ #define loaddebug(thread,register) \extern void fix_processor_context (void );#ifdef CONFIG_ACPI_SLEEP -extern unsigned long saved_eip; -extern unsigned long saved_esp; -extern unsigned long saved_ebp; -extern unsigned long saved_ebx; -extern unsigned long saved_esi; -extern unsigned long saved_edi; +extern unsigned long saved_rip; +extern unsigned long saved_rsp; +extern unsigned long saved_rbp; +extern unsigned long saved_rbx; +extern unsigned long saved_rsi; +extern unsigned long saved_rdi;/* routines for saving/restoring kernel state */ extern int acpi_save_state_mem (void );
Signature · 1 line
1.4.2.rc2.g5209e
Re: [PATCH 26/33] x86_64: 64bit PIC ACPI wakeup
Quoted 5 lines · Eric W. Biederman
I don't have a configuration I can test this but it compiles cleanly and it should work, the code is very similar to the SMP trampoline, which I have tested. At least now the comments about still running in low memory are actually correct.
We would need someone to actually test this before it could be merged. I didn't see anything that tripped me up though.
-Andi
PATCH 27/33 x86_64: Modify discover_ebda to use virtual addresses
In reply to Eric W. Biederman--- arch/x86_64/kernel/setup.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
arch/x86_64/kernel/setup.c +2 -2
@@ -505,10 +505,10 @@ static void discover_ebda(void)* there is a real-mode segmented pointer pointing to the * 4K EBDA area at 0x40E */ - ebda_addr = *(unsigned short *)EBDA_ADDR_POINTER ; + ebda_addr = *(unsigned short *)__va (EBDA_ADDR_POINTER ); ebda_addr <<=4 ; - ebda_size = *(unsigned short *)(unsigned long )ebda_addr; + ebda_size = *(unsigned short *)__va (ebda_addr);/* Round EBDA up to pages */ if (ebda_size ==0 )
Signature · 1 line
1.4.2.rc2.g5209e
PATCH 28/33 x86_64: Remove the identity mapping as early as possible.
In reply to Eric W. BiedermanWith the rewrite of the SMP trampoline and the early page allocator there is nothing that needs identity mapped pages, once we start executing C code.
So add zap_identity_mappings into head64.c and remove zap_low_mappings() from much later in the code. The functions
are subtly different thus the name change.
This also kills boot_level4_pgt which was from an earlier attempt to move the identity mappings as early as possible, and is now no longer needed. Essentially I have replaced boot_level4_pgt with trampoline_level4_pgt in trampoline.S
--- arch/x86_64/kernel/head.S | 34 ++++++++++++++-------------------- arch/x86_64/kernel/head64.c | 16 ++++++++++------ arch/x86_64/kernel/setup.c | 2 -- arch/x86_64/kernel/setup64.c | 1 - arch/x86_64/mm/init.c | 24 ------------------------ include/asm-x86_64/pgtable.h | 1 - include/asm-x86_64/proto.h | 2 -- 7 files changed, 24 insertions(+), 56 deletions(-)
arch/x86_64/kernel/head.S +14 -20
@@ -73,7 +73,7 @@ startup_32: movl %eax, %cr4 /* Setup early boot stage 4 level pagetables */ - movl $(boot_level4_pgt - __START_KERNEL_map), %eax + movl $(init_level4_pgt - __START_KERNEL_map), %eax movl %eax, %cr3 /* Setup EFER (Extended Feature Enable Register) */
@@ -117,7 +117,7 @@ ENTRY(secondary_startup_64) movq %rax, %cr4 /* Setup early boot stage 4 level pagetables. */ - movq $(boot_level4_pgt - __START_KERNEL_map), %rax + movq $(init_level4_pgt - __START_KERNEL_map), %rax movq %rax, %cr3 /* Check if nx is implemented */
@@ -264,9 +264,19 @@ #define PMDS(START, PERM, COUNT) \ i = i + 1 ; \ .endr + /* + * This default setting generates an ident mapping at address 0x100000 + * and a mapping for the kernel that precisely maps virtual address + * 0xffffffff80000000 to physical address 0x000000. (always using + * 2Mbyte large pages provided by PAE mode) + */ NEXT_PAGE(init_level4_pgt) - /* This gets initialized in x86_64_start_kernel */ - .fill 512,8,0 + .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE + .fill 257,8,0 + .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE + .fill 252,8,0 + /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */ + .quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE NEXT_PAGE(level3_ident_pgt) .quad level2_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
@@ -301,22 +311,6 @@ #undef NEXT_PAGE #ifndef CONFIG_HOTPLUG_CPU __INITDATA #endif - /* - * This default setting generates an ident mapping at address 0x100000 - * and a mapping for the kernel that precisely maps virtual address - * 0xffffffff80000000 to physical address 0x000000. (always using - * 2Mbyte large pages provided by PAE mode) - */ - .align PAGE_SIZE -ENTRY(boot_level4_pgt) - .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE - .fill 257,8,0 - .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE - .fill 252,8,0 - /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */ - .quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE - - .data .align 16 .globl cpu_gdt_descr
arch/x86_64/kernel/head64.c +10 -6
@@ -18,8 +18,16 @@ #include <asm/bootsetup.h>#include <asm/setup.h> #include <asm/desc.h> #include <asm/pgtable.h> +#include <asm/tlbflush.h> #include <asm/sections.h> +static void __init zap_identity_mappings (void ) +{ +pgd_t *pgd =pgd_offset_k (0UL ); +pgd_clear (pgd); +__flush_tlb (); +} +/* Don't add a printk in there. printk relies on the PDA which is not initialized yet. */ static void __init clear_bss (void )
@@ -78,6 +86,8 @@ void __init x86_64_start_kernel(char * rchar *s;int i; +/* Make NULL pointers segfault */ +zap_identity_mappings ();for (i =0 ; i <256 ; i++)set_intr_gate (i, early_idt_handler); asmvolatile ("lidt %0" ::"m" (idt_descr));
@@ -88,12 +98,6 @@ void __init x86_64_start_kernel(char * r*/ lockdep_init (); -/* -* switch to init_level4_pgt from boot_level4_pgt -*/ -memcpy (init_level4_pgt, boot_level4_pgt,PTRS_PER_PGD *sizeof (pgd_t)); - asmvolatile ("movq %0,%%cr3" ::"r" (__pa_symbol (&init_level4_pgt))); -for (i =0 ; i <NR_CPUS ; i++)cpu_pda (i) = &boot_cpu_pda[i];
arch/x86_64/kernel/setup.c +0 -2
@@ -568,8 +568,6 @@ #endifdmi_scan_machine (); -zap_low_mappings (0 ); -#ifdef CONFIG_ACPI /* * Initialize the ACPI boot-time table parser (gets the RSDP and SDT).
arch/x86_64/kernel/setup64.c +0 -1
@@ -197,7 +197,6 @@ void __cpuinit cpu_init (void)/* CPU 0 is initialised in head64.c */ if (cpu !=0 ) {pda_init (cpu); -zap_low_mappings (cpu); }else estacks = boot_exception_stacks;
arch/x86_64/mm/init.c +0 -24
@@ -332,21 +332,6 @@ void __init init_memory_mapping(unsigned__flush_tlb_all (); } -void __cpuinit zap_low_mappings (int cpu) -{ -if (cpu ==0 ) { -pgd_t *pgd =pgd_offset_k (0UL ); -pgd_clear (pgd); - }else { -/* -* For AP's, zap the low identity mappings by changing the cr3 -* to init_level4_pgt and doing local flush tlb all -*/ - asmvolatile ("movq %0,%%cr3" ::"r" (__pa_symbol (&init_level4_pgt))); - } -__flush_tlb_all (); -} -/* Compute zone sizes for the DMA and DMA32 zones in a node. */ __init void size_zones(unsigned long *z, unsigned long *h,
@@ -667,15 +652,6 @@ #endif reservedpages << (PAGE_SHIFT -10 ), datasize >>10 , initsize >> 10); - -#ifdef CONFIG_SMP -/* -* Sync boot_level4_pgt mappings with the init_level4_pgt -* except for the low identity mappings which are already zapped -* in init_level4_pgt. This sync-up is essential for AP's bringup -*/ -memcpy (boot_level4_pgt+1 , init_level4_pgt+1 , (PTRS_PER_PGD -1 )*sizeof (pgd_t)); -#endif }void free_init_pages (char *what,unsigned long begin,unsigned long end)
include/asm-x86_64/pgtable.h +0 -1
@@ -18,7 +18,6 @@ extern pud_t level3_kernel_pgt[512];extern pud_t level3_ident_pgt[512 ];extern pmd_t level2_kernel_pgt[512 ];extern pgd_t init_level4_pgt[]; -extern pgd_t boot_level4_pgt[];extern unsigned long __supported_pte_mask;#define swapper_pg_dir init_level4_pgt
include/asm-x86_64/proto.h +0 -2
@@ -11,8 +11,6 @@ struct pt_regs;extern void start_kernel (void );extern void pda_init (int ); -extern void zap_low_mappings (int cpu); -extern void early_idt_handler (void );extern void mcheck_init (struct cpuinfo_x86 *c);
Signature · 1 line
1.4.2.rc2.g5209e
Re: [PATCH 28/33] x86_64: Remove the identity mapping as early as possible.
Quoted 3 lines · Eric W. Biederman
With the rewrite of the SMP trampoline and the early page allocator there is nothing that needs identity mapped pages, once we start executing C code.
Cool.
Hopefully that can be done for i386 too. People on other architectures have been complaining that i386 doesn't catch early NULL pointers.
-Andi
PATCH 29/33 x86_64: __pa and __pa_symbol address space separation
In reply to Eric W. BiedermanCurrently __pa_symbol is for use with symbols in the kernel address map and __pa is for use with pointers into the physical memory map. But the code is implemented so you can usually interchange the two.
__pa which is much more common can be implemented much more cheaply if it is it doesn't have to worry about any other kernel address spaces. This is especially true with a relocatable kernel as __pa_symbol needs to peform an extra variable read to resolve the address.
There is a third macro that is added for the vsyscall data __pa_vsymbol for finding the physical addesses of vsyscall pages.
Most of this patch is simply sorting through the references to __pa or __pa_symbol and using the proper one. A little of it is continuing to use a physical address when we have it instead of recalculating it several times.
swapper_pgd is now NULL. leave_mm now uses init_mm.pgd and init_mm.pgd is initialized at boot (instead of compile time) to the physmem virtual mapping of init_level4_pgd. The physical address changed.
Except for the for EMPTY_ZERO page all of the remaining references to __pa_symbol appear to be during kernel initialization. So this should reduce the cost of __pa in the common case, even on a relocated kernel.
As this is technically a semantic change we need to be on the lookout for anything I missed. But it works for me (tm).
--- arch/i386/kernel/alternative.c | 8 ++++---- arch/i386/mm/init.c | 15 ++++++++------- arch/x86_64/kernel/setup.c | 9 +++++---- arch/x86_64/kernel/smp.c | 2 +- arch/x86_64/kernel/vsyscall.c | 10 ++++++++-- arch/x86_64/mm/init.c | 21 +++++++++++---------- arch/x86_64/mm/pageattr.c | 20 +++++++++++--------- include/asm-x86_64/page.h | 6 ++---- include/asm-x86_64/pgtable.h | 4 ++-- 9 files changed, 52 insertions(+), 43 deletions(-)
arch/i386/kernel/alternative.c +4 -4
@@ -347,8 +347,8 @@ void __init alternative_instructions(voiif (no_replacement) {printk (KERN_INFO "(SMP-)alternatives turned off\n" );free_init_pages ("SMP alternatives" , - (unsigned long )__smp_alt_begin, - (unsigned long )__smp_alt_end); +__pa_symbol (&__smp_alt_begin), +__pa_symbol (&__smp_alt_end));return ; }apply_alternatives (__alt_instructions, __alt_instructions_end);
@@ -375,8 +375,8 @@ #ifdef CONFIG_SMP _text, _etext); }free_init_pages ("SMP alternatives" , - (unsigned long )__smp_alt_begin, - (unsigned long )__smp_alt_end); +__pa_symbol (&__smp_alt_begin), +__pa_symbol (&__smp_alt_end)); }else {alternatives_smp_save (__smp_alt_instructions, __smp_alt_instructions_end);
arch/i386/mm/init.c +8 -7
@@ -750,10 +750,11 @@ void free_init_pages(char *what, unsigneunsigned long addr;for (addr = begin; addr < end; addr +=PAGE_SIZE ) { -ClearPageReserved (virt_to_page (addr)); -init_page_count (virt_to_page (addr)); -memset ((void *)addr,POISON_FREE_INITMEM ,PAGE_SIZE ); -free_page (addr); +struct page *page =pfn_to_page (addr >>PAGE_SHIFT ); +ClearPageReserved (page); +init_page_count (page); +memset (page_address (page),POISON_FREE_INITMEM ,PAGE_SIZE ); +__free_page (page); totalram_pages++; }printk (KERN_INFO "Freeing %s: %ldk freed\n" , what, (end - begin) >>10 );
@@ -762,14 +763,14 @@ void free_init_pages(char *what, unsignevoid free_initmem (void ) {free_init_pages ("unused kernel memory" , - (unsigned long )(&__init_begin), - (unsigned long )(&__init_end)); +__pa_symbol (&__init_begin), +__pa_symbol (&__init_end)); }#ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem (unsigned long start,unsigned long end) { -free_init_pages ("initrd memory" , start, end); +free_init_pages ("initrd memory" ,__pa (start),__pa (end)); }#endif
arch/x86_64/kernel/setup.c +5 -4
@@ -543,11 +543,12 @@ #endif init_mm.end_code = (unsigned long ) &_etext; init_mm.end_data = (unsigned long ) &_edata; init_mm.brk = (unsigned long ) &_end; + init_mm.pgd =__va (__pa_symbol (&init_level4_pgt)); - code_resource.start =virt_to_phys (&_text); - code_resource.end =virt_to_phys (&_etext)-1 ; - data_resource.start =virt_to_phys (&_etext); - data_resource.end =virt_to_phys (&_edata)-1 ; + code_resource.start =__pa_symbol (&_text); + code_resource.end =__pa_symbol (&_etext)-1 ; + data_resource.start =__pa_symbol (&_etext); + data_resource.end =__pa_symbol (&_edata)-1 ;parse_cmdline_early (cmdline_p);
arch/x86_64/kernel/smp.c +1 -1
@@ -76,7 +76,7 @@ static inline void leave_mm(int cpu)if (read_pda (mmu_state) ==TLBSTATE_OK )BUG ();cpu_clear (cpu,read_pda (active_mm)->cpu_vm_mask); -load_cr3 (swapper_pg_dir); +load_cr3 (init_mm.pgd); }/*
arch/x86_64/kernel/vsyscall.c +8 -2
@@ -41,6 +41,12 @@ seqlock_t __xtime_lock __section_xtime_l#include <asm/unistd.h> +#define __pa_vsymbol (x) \ + ({unsigned long v; \ + extern char __vsyscall_0; \ + asm("" : "=r" (v) : "0" (x)); \ + ((v - VSYSCALL_FIRST_PAGE) + __pa_symbol(&__vsyscall_0)); }) + static __always_inline void timeval_normalize(struct timeval * tv) {time_t __sec;
@@ -155,10 +161,10 @@ static int vsyscall_sysctl_change(ctl_tareturn ret;/* gcc has some trouble with __va(__pa()), so just do it this way. */ - map1 =ioremap (__pa_symbol (&vsysc1),2 ); + map1 =ioremap (__pa_vsymbol (&vsysc1),2 );if (!map1)return -ENOMEM ; - map2 =ioremap (__pa_symbol (&vsysc2),2 ); + map2 =ioremap (__pa_vsymbol (&vsysc2),2 );if (!map2) { ret = -ENOMEM ; goto out;
arch/x86_64/mm/init.c +11 -10
@@ -663,11 +663,11 @@ void free_init_pages(char *what, unsigneprintk (KERN_INFO "Freeing %s: %ldk freed\n" , what, (end - begin) >>10 );for (addr = begin; addr < end; addr +=PAGE_SIZE ) { -ClearPageReserved (virt_to_page (addr)); -init_page_count (virt_to_page (addr)); -memset ((void *)(addr & ~(PAGE_SIZE -1 )), -POISON_FREE_INITMEM ,PAGE_SIZE ); -free_page (addr); +struct page *page =pfn_to_page (addr >>PAGE_SHIFT ); +ClearPageReserved (page); +init_page_count (page); +memset (page_address (page),POISON_FREE_INITMEM ,PAGE_SIZE ); +__free_page (page); totalram_pages++; } }
@@ -677,17 +677,18 @@ void free_initmem(void)memset (__initdata_begin,POISON_FREE_INITDATA , __initdata_end - __initdata_begin);free_init_pages ("unused kernel memory" , - (unsigned long )(&__init_begin), - (unsigned long )(&__init_end)); +__pa_symbol (&__init_begin), +__pa_symbol (&__init_end)); }#ifdef CONFIG_DEBUG_RODATA void mark_rodata_ro (void ) { -unsigned long addr = (unsigned long )__start_rodata; +unsigned long addr = (unsigned long )__va (__pa_symbol (&__start_rodata)); +unsigned long end = (unsigned long )__va (__pa_symbol (&__end_rodata)); -for (; addr < (unsigned long )__end_rodata; addr +=PAGE_SIZE ) +for (; addr < end; addr +=PAGE_SIZE )change_page_attr_addr (addr,1 ,PAGE_KERNEL_RO ); printk ("Write protecting the kernel read-only data: %luk\n",
@@ -706,7 +707,7 @@ #endif#ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem (unsigned long start,unsigned long end) { -free_init_pages ("initrd memory" , start, end); +free_init_pages ("initrd memory" ,__pa (start),__pa (end)); }#endif
arch/x86_64/mm/pageattr.c +11 -9
@@ -51,7 +51,6 @@ static struct page *split_large_page(unsSetPagePrivate (base);page_private (base) =0 ; - address =__pa (address); addr = address &LARGE_PAGE_MASK ; pbase = (pte_t *)page_address (base);for (i =0 ; i <PTRS_PER_PTE ; i++, addr +=PAGE_SIZE ) {
@@ -95,7 +94,7 @@ static inline void save_page(struct page* No more special protections in this 2/4MB area - revert to a * large page again. */ -static void revert_page (unsigned long address,pgprot_t ref_prot) +static void revert_page (unsigned long address,unsigned long pfn,pgprot_t ref_prot) {pgd_t *pgd;pud_t *pud;
@@ -109,7 +108,7 @@ static void revert_page(unsigned long ad pmd =pmd_offset (pud, address);BUG_ON (pmd_val (*pmd) & _PAGE_PSE);pgprot_val (ref_prot) |= _PAGE_PSE; - large_pte =mk_pte_phys (__pa (address) &LARGE_PAGE_MASK , ref_prot); + large_pte =mk_pte_phys ((pfn <<PAGE_SHIFT ) &LARGE_PAGE_MASK , ref_prot);set_pte ((pte_t *)pmd, large_pte); }
@@ -137,7 +136,7 @@ __change_page_attr(unsigned long addressstruct page *split; ref_prot2 =__pgprot (pgprot_val (pte_pgprot (*lookup_address (address))) & ~(1 <<_PAGE_BIT_PSE)); - split =split_large_page (address, prot, ref_prot2); + split =split_large_page (pfn <<PAGE_SHIFT , prot, ref_prot2);if (!split)return -ENOMEM ;set_pte (kpte,mk_pte (split, ref_prot2));
@@ -156,7 +155,7 @@ __change_page_attr(unsigned long addressif (page_private (kpte_page) ==0 ) {save_page (kpte_page); -revert_page (address, ref_prot); +revert_page (address, pfn, ref_prot); }return 0 ; }
@@ -176,6 +175,7 @@ __change_page_attr(unsigned long address*/ int change_page_attr_addr (unsigned long address,int numpages,pgprot_t prot) { +unsigned long phys_base_pfn =__pa_symbol (__START_KERNEL_map) >>PAGE_SHIFT ;int err =0 ;int i;
@@ -188,14 +188,16 @@ int change_page_attr_addr(unsigned longbreak ;/* Handle kernel mapping too which aliases part of the * lowmem */ -if (__pa (address) <KERNEL_TEXT_SIZE ) { +if ((pfn >= phys_base_pfn) && + ((pfn - phys_base_pfn) < (KERNEL_TEXT_SIZE >>PAGE_SHIFT ))) + {unsigned long addr2;pgprot_t prot2 = prot; - addr2 = __START_KERNEL_map +__pa (address); + addr2 = __START_KERNEL_map + ((pfn - phys_base_pfn) <<PAGE_SHIFT );pgprot_val (prot2) &= ~_PAGE_NX; err =__change_page_attr (addr2, pfn, prot2,PAGE_KERNEL_EXEC ); - } - } + } + }up_write (&init_mm.mmap_sem);return err; }
include/asm-x86_64/page.h +2 -4
@@ -102,17 +102,15 @@ #define PAGE_OFFSET __PAGE_OFFSET/* Note: __pa(&symbol_visible_to_c) should be always replaced with __pa_symbol. Otherwise you risk miscompilation. */ -#define __pa (x) (((unsigned long)(x)>=__START_KERNEL_map)?(unsigned long)(x) - (unsigned long)__START_KERNEL_map:(unsigned long)(x) - PAGE_OFFSET) +#define __pa (x) ((unsigned long)(x) - PAGE_OFFSET)/* __pa_symbol should be used for C visible symbols. This seems to be the official gcc blessed way to do such arithmetic. */ #define __pa_symbol (x) \ ({unsigned long v; \ asm("" : "=r" (v) : "0" (x)); \ - __pa(v); }) + (v - __START_KERNEL_map); })#define __va (x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) -#define __boot_va (x) __va(x) -#define __boot_pa (x) __pa(x)#ifdef CONFIG_FLATMEM #define pfn_valid (pfn) ((pfn) < end_pfn)#endif
include/asm-x86_64/pgtable.h +2 -2
@@ -20,7 +20,7 @@ extern pmd_t level2_kernel_pgt[512];extern pgd_t init_level4_pgt[];extern unsigned long __supported_pte_mask; -#define swapper_pg_dir init_level4_pgt +#define swapper_pg_dir ((pgd_t *)NULL)extern int nonx_setup (char *str);extern void paging_init (void );
@@ -33,7 +33,7 @@ extern unsigned long pgkern_mask;* for zero-mapped memory areas etc.. */ extern unsigned long empty_zero_page[PAGE_SIZE /sizeof (unsigned long )]; -#define ZERO_PAGE (vaddr) (virt_to_page(empty_zero_page)) +#define ZERO_PAGE (vaddr) (pfn_to_page(__pa_symbol(&empty_zero_page) >> PAGE_SHIFT))#endif /* !__ASSEMBLY__ */
Signature · 1 line
1.4.2.rc2.g5209e
PATCH 30/33 x86_64: Remove CONFIG_PHYSICAL_START
In reply to Eric W. BiedermanI am about to add relocatable kernel support which has essentially no cost so there is no point in retaining CONFIG_PHYSICAL_START and retaining CONFIG_PHYSICAL_START makes implementation of and testing of a relocatable kernel more difficult.
--- arch/x86_64/Kconfig | 19 ------------------- arch/x86_64/boot/compressed/head.S | 6 +++--- arch/x86_64/boot/compressed/misc.c | 6 +++--- arch/x86_64/defconfig | 1 - arch/x86_64/kernel/vmlinux.lds.S | 2 +- arch/x86_64/mm/fault.c | 4 ++-- include/asm-x86_64/page.h | 2 -- 7 files changed, 9 insertions(+), 31 deletions(-)
arch/x86_64/Kconfig +0 -19
@@ -486,25 +486,6 @@ config CRASH_DUMP help Generate crash dump after being started by kexec. -config PHYSICAL_START - hex "Physical address where the kernel is loaded" if (EMBEDDED || CRASH_DUMP) - default "0x1000000" if CRASH_DUMP - default "0x200000" - help - This gives the physical address where the kernel is loaded. Normally - for regular kernels this value is 0x200000 (2MB). But in the case - of kexec on panic the fail safe kernel needs to run at a different - address than the panic-ed kernel. This option is used to set the load - address for kernels used to capture crash dump on being kexec'ed - after panic. The default value for crash dump kernels is - 0x1000000 (16MB). This can also be set based on the "X" value as - specified in the "crashkernel=YM@XM" command line boot parameter - passed to the panic-ed kernel. Typically this parameter is set as - crashkernel=64M@16M. Please take a look at - Documentation/kdump/kdump.txt for more details about crash dumps. - - Don't change this unless you know what you are doing. - config SECCOMP bool "Enable seccomp to safely compute untrusted bytecode" depends on PROC_FS
arch/x86_64/boot/compressed/head.S +3 -3
@@ -76,7 +76,7 @@ startup_32: jnz 3f addl $8,%esp xorl %ebx,%ebx - ljmp $(__KERNEL_CS), $__PHYSICAL_START + ljmp $(__KERNEL_CS), $0x200000 /* * We come here, if we were loaded high.
@@ -102,7 +102,7 @@ startup_32: popl %ecx # lcount popl %edx # high_buffer_start popl %eax # hcount - movl $__PHYSICAL_START,%edi + movl $0x200000,%edi cli # make sure we don't get interrupted ljmp $(__KERNEL_CS), $0x1000 # and jump to the move routine
@@ -127,7 +127,7 @@ move_routine_start: movsl movl %ebx,%esi # Restore setup pointer xorl %ebx,%ebx - ljmp $(__KERNEL_CS), $__PHYSICAL_START + ljmp $(__KERNEL_CS), $0x200000 move_routine_end:
arch/x86_64/boot/compressed/misc.c +3 -3
@@ -288,7 +288,7 @@ #ifdef STANDARD_MEMORY_BIOS_CALL#else if ((RM_ALT_MEM_K >RM_EXT_MEM_K ?RM_ALT_MEM_K :RM_EXT_MEM_K ) <1024 )error ("Less than 2MB of memory" );#endif - output_data = (unsigned char *)__PHYSICAL_START;/* Normally Points to 1M */ + output_data = (unsigned char *)0x200000 ; free_mem_end_ptr = (long )real_mode; }
@@ -311,8 +311,8 @@ #endif low_buffer_size = low_buffer_end -LOW_BUFFER_START ; high_loaded =1 ; free_mem_end_ptr = (long )high_buffer_start; -if ( (__PHYSICAL_START + low_buffer_size) > ((ulg )high_buffer_start)) { - high_buffer_start = (uch *)(__PHYSICAL_START + low_buffer_size); +if ( (0x200000 + low_buffer_size) > ((ulg )high_buffer_start)) { + high_buffer_start = (uch *)(0x200000 + low_buffer_size); mv->hcount =0 ;/* say: we need not to move high_buffer */ }else mv->hcount =-1 ;
arch/x86_64/defconfig +0 -1
@@ -158,7 +158,6 @@ CONFIG_X86_MCE_INTEL=y CONFIG_X86_MCE_AMD=y # CONFIG_KEXEC is not set # CONFIG_CRASH_DUMP is not set -CONFIG_PHYSICAL_START=0x200000 CONFIG_SECCOMP=y # CONFIG_HZ_100 is not set CONFIG_HZ_250=y
arch/x86_64/kernel/vmlinux.lds.S +1 -1
@@ -15,7 +15,7 @@ ENTRY(phys_startup_64) jiffies_64 = jiffies; SECTIONS { - . = __START_KERNEL; + . = __START_KERNEL_map + 0x200000; phys_startup_64 = startup_64 - LOAD_OFFSET; _text = .; /* Text and read-only data */ .text : AT(ADDR(.text) - LOAD_OFFSET) {
arch/x86_64/mm/fault.c +2 -2
@@ -650,9 +650,9 @@ void vmalloc_sync_all(void) start = address +PGDIR_SIZE ; }/* Check that there is no need to do the same for the modules area. */ -BUILD_BUG_ON (!(MODULES_VADDR > __START_KERNEL)); +BUILD_BUG_ON (!(MODULES_VADDR > __START_KERNEL_map));BUILD_BUG_ON (!(((MODULES_END -1 ) &PGDIR_MASK ) == - (__START_KERNEL &PGDIR_MASK ))); + (__START_KERNEL_map &PGDIR_MASK ))); }static int __init enable_pagefaulttrace (char *str)
include/asm-x86_64/page.h +0 -2
@@ -75,8 +75,6 @@ #define __pgprot(x) ((pgprot_t) { (x) }#endif /* !__ASSEMBLY__ */ -#define __PHYSICAL_START _AC(CONFIG_PHYSICAL_START,UL) -#define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START)#define __START_KERNEL_map _AC(0xffffffff80000000,UL)#define __PAGE_OFFSET _AC(0xffff810000000000,UL)
Signature · 1 line
1.4.2.rc2.g5209e
PATCH 31/33 x86_64 boot: Add serial output support to the decompressor
In reply to Eric W. BiedermanThis patch does two very simple things.
It adds a serial output capability to the decompressor. It adds a command line parser for the early_printk option so we know which output method to use for the decompressor.
This makes debugging the decompressor a little easier, and keeps us from assuming we always have a vga console on all hardware.
--- arch/x86_64/boot/compressed/Makefile | 2 arch/x86_64/boot/compressed/misc.c | 262 ++++++++++++++++++++++++++++++++-- 2 files changed, 248 insertions(+), 16 deletions(-)
arch/x86_64/boot/compressed/Makefile +1 -1
@@ -11,7 +11,7 @@ EXTRA_AFLAGS := -traditional -m32 # cannot use EXTRA_CFLAGS because base CFLAGS contains -mkernel which conflicts with # -m32 -CFLAGS := -m32 -D__KERNEL__ -Iinclude -O2 -fno-strict-aliasing +CFLAGS := -m32 -D__KERNEL__ -Iinclude -O2 -fno-strict-aliasing -fno-builtin LDFLAGS := -m elf_i386 LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32 -m elf_i386
arch/x86_64/boot/compressed/misc.c +247 -15
345 lines not on this page · raw message
Signature · 1 line
1.4.2.rc2.g5209e
PATCH 32/33 x86_64: Relocatable kernel support
In reply to Eric W. BiedermanThis patch modifies the x86_64 kernel so that it can be loaded and run at any 2M aligned address, below 512G. The technique used is to compile the decompressor with -fPIC and modify it so the decompressor is fully relocatable. For the main kernel the page tables are modified so the kernel remains at the same virtual address. In addition a variable phys_base is kept that holds the physical address the kernel is loaded at. __pa_symbol is modified to add that when we take the address of a kernel symbol.
When loaded with a normal bootloader the decompressor will decompress the kernel to 2M and it will run there. This both ensures the relocation code is always working, and makes it easier to use 2M pages for the kernel and the cpu.
--- arch/x86_64/boot/compressed/Makefile | 13 + arch/x86_64/boot/compressed/head.S | 301 ++++++++++++++++++++++--------- arch/x86_64/boot/compressed/misc.c | 248 +++++++++++++------------- arch/x86_64/boot/compressed/vmlinux.lds | 44 +++++ arch/x86_64/boot/compressed/vmlinux.scr | 5 - arch/x86_64/kernel/head.S | 226 +++++++++++++---------- arch/x86_64/kernel/vmlinux.lds.S | 2 include/asm-x86_64/page.h | 6 - 8 files changed, 527 insertions(+), 318 deletions(-)
arch/x86_64/boot/compressed/Makefile +6 -7
@@ -7,16 +7,15 @@ # Note all the files here are compiled/l # targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o -EXTRA_AFLAGS := -traditional -m32 +EXTRA_AFLAGS := -traditional # cannot use EXTRA_CFLAGS because base CFLAGS contains -mkernel which conflicts with -# -m32 -CFLAGS := -m32 -D__KERNEL__ -Iinclude -O2 -fno-strict-aliasing -fno-builtin -LDFLAGS := -m elf_i386 +CFLAGS := -m64 -D__KERNEL__ -Iinclude -O2 -fno-strict-aliasing -fPIC -mcmodel=small -fno-builtin +LDFLAGS := -m elf_x86_64 -LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32 -m elf_i386 +LDFLAGS_vmlinux := -T -$(obj)/vmlinux: $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE +$(obj)/vmlinux: $(src)/vmlinux.lds $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE $(call if_changed,ld) @:
@@ -26,7 +25,7 @@ LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE $(call if_changed,gzip) -LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T +LDFLAGS_piggy.o := -r --format binary --oformat elf64-x86-64 -T $(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE $(call if_changed,ld)
arch/x86_64/boot/compressed/head.S +215 -86
331 lines not on this page · raw message
arch/x86_64/boot/compressed/misc.c +130 -118
316 lines not on this page · raw message
arch/x86_64/boot/compressed/vmlinux.lds new file +44 -0
44 lines not on this page · raw message
arch/x86_64/boot/compressed/vmlinux.scr +3 -2
@@ -1,9 +1,10 @@ SECTIONS { - .data : { + .text.compressed : { input_len = .; LONG(input_data_end - input_data) input_data = .; - *(.data) + *(.data) + output_len = . - 4; input_data_end = .; } }
arch/x86_64/kernel/head.S +124 -102
297 lines not on this page · raw message
arch/x86_64/kernel/vmlinux.lds.S +1 -1
@@ -15,7 +15,7 @@ ENTRY(phys_startup_64) jiffies_64 = jiffies; SECTIONS { - . = __START_KERNEL_map + 0x200000; + . = __START_KERNEL_map; phys_startup_64 = startup_64 - LOAD_OFFSET; _text = .; /* Text and read-only data */ .text : AT(ADDR(.text) - LOAD_OFFSET) {
include/asm-x86_64/page.h +4 -2
@@ -61,6 +61,8 @@ #define PTE_MASK PHYSICAL_PAGE_MASKtypedef struct {unsigned long pgprot; }pgprot_t ; +extern unsigned long phys_base; +#define pte_val (x) ((x).pte)#define pmd_val (x) ((x).pmd)#define pud_val (x) ((x).pud)
@@ -99,14 +101,14 @@ #endif /* __ASSEMBLY__ */#define PAGE_OFFSET __PAGE_OFFSET/* Note: __pa(&symbol_visible_to_c) should be always replaced with __pa_symbol. -Otherwise you risk miscompilation. */ +Otherwise you risk miscompilation. */ #define __pa (x) ((unsigned long)(x) - PAGE_OFFSET)/* __pa_symbol should be used for C visible symbols. This seems to be the official gcc blessed way to do such arithmetic. */ #define __pa_symbol (x) \ ({unsigned long v; \ asm("" : "=r" (v) : "0" (x)); \ - (v - __START_KERNEL_map); }) + ((v - __START_KERNEL_map) + phys_base); })#define __va (x) ((void *)((unsigned long)(x)+PAGE_OFFSET))#ifdef CONFIG_FLATMEM
Signature · 1 line
1.4.2.rc2.g5209e
Re: [PATCH 32/33] x86_64: Relocatable kernel support
Quoted 5 lines · Eric W. Biederman
When loaded with a normal bootloader the decompressor will decompress the kernel to 2M and it will run there. This both ensures the relocation code is always working, and makes it easier to use 2M pages for the kernel and the cpu.
It would have been nicer if you had moved the uncompressor to be 64bit first like it was planned for a long time.
-Andi
Re: [PATCH 32/33] x86_64: Relocatable kernel support
Quoted 9 lines · Andi Kleen
Quoted 5 lines · Eric W. Biederman
When loaded with a normal bootloader the decompressor will decompress the kernel to 2M and it will run there. This both ensures the relocation code is always working, and makes it easier to use 2M pages for the kernel and the cpu.
It would have been nicer if you had moved the uncompressor to be 64bit first like it was planned for a long time.
Sorry. I wasn't really in those discussions.
I guess I could take this in some slightly smaller steps. But this does wind up with decompressor being 64bit code.
Eric
Re: [PATCH 32/33] x86_64: Relocatable kernel support
Quoted 2 lines · Eric W. Biederman
I guess I could take this in some slightly smaller steps. But this does wind up with decompressor being 64bit code.
Sorry to bring out the old mail.
except reusing the uncompressor in 32bit, is there any reason that you removed startup_32 for vmlinux but keep startup_32 for bzImage?
that will make vmlinux use 64bit boot loader only.
YH
Re: [PATCH 32/33] x86_64: Relocatable kernel support
Quoted 10 lines · Yinghai Lu
Quoted 2 lines · Eric W. Biederman
I guess I could take this in some slightly smaller steps. But this does wind up with decompressor being 64bit code.
Sorry to bring out the old mail.
except reusing the uncompressor in 32bit, is there any reason that you removed
startup_32for vmlinux but keepstartup_32for bzImage?that will make vmlinux use 64bit boot loader only.
If you are booting a vmlinux you read the ELF header. The ELF header only describes the native mode. Therefore no 32bit entry makes much sense.
bzImage is something else entirely.
Eric
Re: [PATCH 32/33] x86_64: Relocatable kernel support
Quoted 3 lines · Eric W. Biederman
If you are booting a vmlinux you read the ELF header. The ELF header only describes the native mode. Therefore no 32bit entry makes much sense.
Yes, but if you keep the startup_32 and it will be at 0x200000, and startup_64 will be 0x200100. and entry point in ELF header is 0x200100.
by removing startup_32, startup_64 will be 0x200000. and entry point in ehdr is 0x200000.
So I assume entry_point in elf_header could be used by 64bit bootloader and phdr[1].p_addr could be used by 32bit boot loader.
YH
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x200100 Start of program headers: 64 (bytes into file) Start of section headers: 7192496 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 5 Size of section headers: 64 (bytes) Number of section headers: 42
Section header string table index: 39
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000100000 0xffffffff80200000 0x0000000000200000
0x000000000032f508 0x000000000032f508 R E 100000
LOAD 0x0000000000430000 0xffffffff80530000 0x0000000000530000
0x0000000000148ec8 0x0000000000148ec8 RWE 100000
LOAD 0x0000000000600000 0xffffffffff600000 0x0000000000679000
0x0000000000000c08 0x0000000000000c08 RWE 100000
LOAD 0x000000000067a000 0xffffffff8067a000 0x000000000067a000
0x000000000005dd68 0x00000000000e91c8 RWE 100000
NOTE 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 R 8PATCH 33/33 x86_64: Make bzImage a valid 64bit elf executable.
In reply to Eric W. Biederman--- arch/x86_64/boot/Makefile | 2 arch/x86_64/boot/bootsect.S | 93 +++++++++++++++- arch/x86_64/boot/tools/build.c | 232 ++++++++++++++++++++++++++++++++++++---- 3 files changed, 297 insertions(+), 30 deletions(-)
arch/x86_64/boot/Makefile +1 -1
@@ -41,7 +41,7 @@ # -------------------------------------- quiet_cmd_image = BUILD $@ cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/bootsect $(obj)/setup \ - $(obj)/vmlinux.bin $(ROOT_DEV) > $@ + $(obj)/vmlinux.bin $(ROOT_DEV) vmlinux > $@ $(obj)/bzImage: $(obj)/bootsect $(obj)/setup \ $(obj)/vmlinux.bin $(obj)/tools/build FORCE
arch/x86_64/boot/bootsect.S +89 -4
116 lines not on this page · raw message
arch/x86_64/boot/tools/build.c +207 -25
286 lines not on this page · raw message
Signature · 1 line
1.4.2.rc2.g5209e
Quoted 20 lines · Eric W. Biederman
The problem:
We can't always run the kernel at 1MB or 2MB, and so people who need different addresses must build multiple kernels. The bzImage format can't even represent loading a kernel at other than it's default address. With kexec on panic now starting to be used by distros having a kernel not running at the default load address is starting to become common.
The goal of this patch series is to build kernels that are relocatable at run time, and to extend the bzImage format to make it capable of expressing a relocatable kernel.
In extending the bzImage format I am replacing the existing unused bootsector with an ELF header. To express what is going on the ELF header will have type
ET_DYN. Just like the kernel loading anET_DYNexecutable bootloaders are not expected to process relocations. But the executable may be shifted in the address space so long as it's alignment requirements are met.
Quoted 4 lines
The
x86_64kernel is simply built to live at a fixed virtual address and the boot page tables are relocated. The i386 kernel is built to process relocations generated with --embedded-relocs (aftervmlinux.lds.S) has been fixed up to sort out static and dynamic relocations.
Hi Eric,
Can't we use the x86_64 relocation approach for i386 as well? I mean keep the virtual address space fixed and updating the page tables. This would help in the sense that you don't have to change gdb if somebody decides to debug the relocated kernel.
Any such tool that retrieves the symbol virtual address from vmlinux will be confused.
Thanks
Vivek
On Tue, 01 Aug 2006 21:26:28 +0200, Vivek Goyal wrote:
...
Quoted 4 lines
Can't we use the
x86_64relocation approach for i386 as well? I mean keep the virtual address space fixed and updating the page tables. This would help in the sense that you don't have to change gdb if somebody decides to debug the relocated kernel.
This is exactly the approach of mkdump version <=1.0
http://mkdump.sourceforge.net/
As documented by Itsuro Oda:
http://mkdump.cvs.sourceforge.net/mkdump/doc/mini_kernel_tech_note.txt?revision=1.1
There is a problem all the drivers expect that allocated buffer address can be passed directly as physical address to the hardware. mkdump-1.0 has a lot of backward-mappings for these drivers but you can never catch all of them.
Regards,
Lace
Quoted 11 lines · Vivek Goyal
Hi Eric,
Can't we use the
x86_64relocation approach for i386 as well? I mean keep the virtual address space fixed and updating the page tables. This would help in the sense that you don't have to change gdb if somebody decides to debug the relocated kernel.Any such tool that retrieves the symbol virtual address from vmlinux will be confused.
I don't think this is practical given the virtual space constraints on i386 systems.
-hpa
Quoted 10 lines · H. Peter Anvin
Quoted 8 lines · Vivek Goyal
Hi Eric,
Can't we use thex86_64relocation approach for i386 as well? I mean keep the virtual address space fixed and updating the page tables. This would help in the sense that you don't have to change gdb if somebody decides to debug the relocated kernel.
Any such tool that retrieves the symbol virtual address from vmlinux will be confused.
Quoted 2 lines
I don't think this is practical given the virtual space constraints on i386 systems.
Exactly.
Plus it is a lot of dangerous work. Processing is a lot more
conservative.
Eric
Quoted 11 lines · Eric W. Biederman
Currently there are 33 patches in my tree to do this.
The weirdest symptom I have had so far is that page faults did not trigger the early exception handler on
x86_64(instead I got a reboot).There is one outstanding issue where I am probably requiring too much alignment on the
arch/i386kernel.Can anyone find anything else?
I am running into compilation failure on x86_64.
SYSMAP System.map
SYSMAP .tmp_System.map
AS arch/x86_64/boot/bootsect.o
In file included from include/asm/bitops.h:9,
from include/linux/bitops.h:10,
from include/linux/kernel.h:16,
from include/asm/system.h:5,
from include/asm/processor.h:19,
from include/asm/elf.h:11,
from include/linux/elf.h:8,
from arch/x86_64/boot/bootsect.S:20:include/asm/alternative.h:73: error: syntax error in macro parameter list include/asm/alternative.h:88: error: syntax error in macro parameter list include/asm/alternative.h:127: error: syntax error in macro parameter list In file included from include/asm/system.h:5,
from include/asm/processor.h:19,
from include/asm/elf.h:11,
from include/linux/elf.h:8,
from arch/x86_64/boot/bootsect.S:20:
include/linux/kernel.h:34: warning: "ALIGN" redefined
In file included from include/linux/kernel.h:12,
from include/asm/system.h:5,
from include/asm/processor.h:19,
from include/asm/elf.h:11,
from include/linux/elf.h:8,
from arch/x86_64/boot/bootsect.S:20:
include/linux/linkage.h:27: warning: this is the location of the previous definition
In file included from include/asm/system.h:5,
from include/asm/processor.h:19,
from include/asm/elf.h:11,
from include/linux/elf.h:8,
from arch/x86_64/boot/bootsect.S:20:
include/linux/kernel.h:216: error: syntax error in macro parameter list
include/linux/kernel.h:220: error: syntax error in macro parameter list
In file included from include/linux/sched.h:55,
from include/asm/compat.h:9,
from include/asm/elf.h:12,
from include/linux/elf.h:8,
from arch/x86_64/boot/bootsect.S:20:include/linux/nodemask.h:229: error: detected recursion whilst expanding macro "find_first_bit" include/linux/nodemask.h:235: error: detected recursion whilst expanding macro "find_next_bit" include/linux/nodemask.h:254: error: detected recursion whilst expanding macro "find_first_zero_bit" arch/x86_64/boot/bootsect.S:21: error: linux/elf_boot.h: No such file or directory make[1]: *** [arch/x86_64/boot/bootsect.o] Error 1
make: *** [bzImage] Error 2
Thanks
Vivek
Quoted 7 lines · Vivek Goyal
Quoted 6 lines · Eric W. Biederman
Currently there are 33 patches in my tree to do this.
The weirdest symptom I have had so far is that page faults did not trigger the early exception handler on
x86_64(instead I got a reboot).
Quoted 8 lines
Quoted 1 line
There is one outstanding issue where I am probably requiring too much
alignment
Quoted 4 lines
on the
arch/i386kernel.Can anyone find anything else?
I am running into compilation failure on
x86_64.
I'm not quite certain what is wrong, except that you haven't applied all of my patches.
The x86_64 ones do depend on the i386 ones to some extent. That is why it was one giant patchset.
Eric
Quoted 9 lines · Eric W. Biederman
The problem:
We can't always run the kernel at 1MB or 2MB, and so people who need different addresses must build multiple kernels. The bzImage format can't even represent loading a kernel at other than it's default address. With kexec on panic now starting to be used by distros having a kernel not running at the default load address is starting to become common.
Quoted 3 lines
The goal of this patch series is to build kernels that are relocatable at run time, and to extend the bzImage format to make it capable of expressing a relocatable kernel.
Nice work. I'd really like to see support for relocatable kernels in mainline (and kexec-tools!).
Eric, could you please list the advantages of your run-time relocation code over my incomplete relocate-in-userspace prototype posted to fastboot a few weeks ago?
One thing I know for sure is that your implementation supports bzImage while my only supports relocation of vmlinux files. Are there any other uses for relocatable bzImage except kdump?
Thanks!
/ magnus
Quoted 10 lines · Magnus Damm
Quoted 9 lines · Eric W. Biederman
The problem:
We can't always run the kernel at 1MB or 2MB, and so people who need different addresses must build multiple kernels. The bzImage format can't even represent loading a kernel at other than it's default address. With kexec on panic now starting to be used by distros having a kernel not running at the default load address is starting to become common.
Quoted 6 lines
Quoted 3 lines
The goal of this patch series is to build kernels that are relocatable at run time, and to extend the bzImage format to make it capable of expressing a relocatable kernel.
Nice work. I'd really like to see support for relocatable kernels in mainline (and kexec-tools!).
kexec-tools already have initial support for ELF ET_DYN executables. Vivek posted a fix a day two ago so I expect that the support should be working.
Quoted 3 lines
Eric, could you please list the advantages of your run-time relocation code over my incomplete relocate-in-userspace prototype posted to fastboot a few weeks ago?
If you watch an architecture evolve one thing you will notice is that the kinds of relocations keep growing. An ever growing list of things to for the bootloader to do is a pain. Especially when bootloaders generally need to be as simple and as fixed as possible because bootloaders are not something you generally want to update.
Beyond that if you look at head.S the code to process the relocations (after I have finished post processing them at build time) is 9 instructions. Which is absolutely trivial, at least for now.
By keeping the bzImage processing the relocations we have kept the bootloader/kernel interface simple.
Quoted 3 lines
One thing I know for sure is that your implementation supports bzImage while my only supports relocation of vmlinux files. Are there any other uses for relocatable bzImage except kdump?
I can't think of any volume users. A hypervisor that would actually report the real physical addresses would be a candidate. It's a general purpose facility so if it is interesting users will show up. Static relocation has already found another use on x86_64.
There are definitely users of an ELF bzImage beyond the kdump case. Anything that doesn't have a traditional 16bit BIOS on it. LinuxBIOS, and Xen, and some others.
Not having to keep track of anything but your bzImage to boot is also a serious advantage. It's the one binary to rule them all. :)
Eric
Quoted 10 lines · Eric W. Biederman
Quoted 3 lines · Magnus Damm
Eric, could you please list the advantages of your run-time relocation code over my incomplete relocate-in-userspace prototype posted to fastboot a few weeks ago?
If you watch an architecture evolve one thing you will notice is that the kinds of relocations keep growing. An ever growing list of things to for the bootloader to do is a pain. Especially when bootloaders generally need to be as simple and as fixed as possible because bootloaders are not something you generally want to update.
I agree that updating bootloaders is something you want to avoid. I'm not however sure that I would call kexec-tools a bootloader...
Quoted 3 lines
Beyond that if you look at
head.Sthe code to process the relocations (after I have finished post processing them at build time) is 9 instructions. Which is absolutely trivial, at least for now.
Yeah, but the 33 patches are touching more than 9 instructions. =)
Quoted 2 lines
By keeping the bzImage processing the relocations we have kept the bootloader/kernel interface simple.
Agreed. I think your patch makes sense.
Quoted 9 lines
Quoted 3 lines
One thing I know for sure is that your implementation supports bzImage while my only supports relocation of vmlinux files. Are there any other uses for relocatable bzImage except kdump?
I can't think of any volume users. A hypervisor that would actually report the real physical addresses would be a candidate. It's a general purpose facility so if it is interesting users will show up. Static relocation has already found another use on
x86_64.
Quoted 6 lines
There are definitely users of an ELF bzImage beyond the kdump case. Anything that doesn't have a traditional 16bit BIOS on it. LinuxBIOS, and Xen, and some others.
Not having to keep track of anything but your bzImage to boot is also a serious advantage. It's the one binary to rule them all. :)
One binary to rule them all... If that is true, is there any simple way then to extract vmlinux from the bzImage?
Thanks!
/ magnus
Quoted 6 lines · Magnus Damm
Quoted 5 lines · Eric W. Biederman
Quoted 3 lines · Magnus Damm
Eric, could you please list the advantages of your run-time relocation code over my incomplete relocate-in-userspace prototype posted to fastboot a few weeks ago?
Quoted 8 lines
Quoted 5 lines
If you watch an architecture evolve one thing you will notice is that the kinds of relocations keep growing. An ever growing list of things to for the bootloader to do is a pain. Especially when bootloaders generally need to be as simple and as fixed as possible because bootloaders are not something you generally want to update.
I agree that updating bootloaders is something you want to avoid. I'm not however sure that I would call kexec-tools a bootloader...
On the truly insane possibilities. It is actually possible to load a relocated bzImage. run setup16.S below 1M and have it jump to the kernel at any address below 4G.
Quoted 5 lines
Quoted 3 lines
Beyond that if you look at
head.Sthe code to process the relocations (after I have finished post processing them at build time) is 9 instructions. Which is absolutely trivial, at least for now.Yeah, but the 33 patches are touching more than 9 instructions. =)
True. I at of that is general clean ups to allow the kernel to be relocated though. Not to actually perform the relocation.
Quoted 2 lines
One binary to rule them all... If that is true, is there any simple way then to extract vmlinux from the bzImage?
Unfortunately the process is a little lossy :(
So that still means you still need the vmlinux to get the debug symbols.
Eric
Quoted 3 lines
There is one outstanding issue where I am probably requiring too much alignment on the
arch/i386kernel.
There was posts awhile ago about optimizing the kernel performance by loading it at a 4MB offset.
http://www.lkml.org/lkml/2006/2/23/189
Your changes breaks that on i386 (not aligned on a 4MB boundary). But a 5MB offset works. Is that the correct update or does that break the original idea?
Cheers,
Don
Quoted 5 lines · Don Zickus
Quoted 2 lines
There is one outstanding issue where I am probably requiring too much
alignment
Quoted 1 line
on the
arch/i386kernel.
Quoted 8 lines
There was posts awhile ago about optimizing the kernel performance by loading it at a 4MB offset.
http://www.lkml.org/lkml/2006/2/23/189
Your changes breaks that on i386 (not aligned on a 4MB boundary). But a 5MB offset works. Is that the correct update or does that break the original idea?
That patch should still apply and work as described.
Actually when this stuipd cold I have stops slowing me down, and I fix the alignment to what it really needs to be ~= 8KB.
Then bootloaders should be able to make the decision.
HPA Does that sound at all interesting?
Eric
Quoted 14 lines · Eric W. Biederman
Quoted 11 lines · Don Zickus
Quoted 1 line
There is one outstanding issue where I am probably requiring too much
alignment
Quoted 1 line
on the
arch/i386kernel.There was posts awhile ago about optimizing the kernel performance by loading it at a 4MB offset.
http://www.lkml.org/lkml/2006/2/23/189
Your changes breaks that on i386 (not aligned on a 4MB boundary). But a 5MB offset works. Is that the correct update or does that break the original idea?
Quoted 9 lines
That patch should still apply and work as described.
Actually when this stuipd cold I have stops slowing me down, and I fix the alignment to what it really needs to be ~= 8KB.
Then bootloaders should be able to make the decision.
HPA Does that sound at all interesting?
I'm sorry, it's not clear to me what you're asking here.
The bootloaders will load bzImage at the 1 MB point, and it's up to the decompressor to locate it appropriately. It has (correctly) been pointed out that it would be faster if the decompressed kernel is located to the 4 MB point -- large pages don't work below 2/4 MB due to interference with the fixed MTRRs -- but that's doesn't affect the boot protocol in any way.
I was under the impression that your relocatable patches allows the boot loader to load the bzImage at a different address than the usual 0x100000; but again, that shouldn't affect the kernel's final resting place.
-hpa
Quoted 9 lines · Eric W. Biederman
The problem:
We can't always run the kernel at 1MB or 2MB, and so people who need different addresses must build multiple kernels. The bzImage format can't even represent loading a kernel at other than it's default address. With kexec on panic now starting to be used by distros having a kernel not running at the default load address is starting to become common.
Hi Eric,
There seems to be a small anomaly in the current set of patches for i386.
For example if one compiles the kernel with CONFIG_RELOCATABLE=y and CONFIG_PHYSICAL_START=0x400000 (4MB) and he uses grub to load the kernel then kernel would run from 1MB location. I think user would expect it to run from 4MB location.
I think distro's might want to keep above config options enabled. CONFIG_RELOCATABLE=y so that kexec can load kdump kernel at a different address and CONFIG_PHYSICAL_START=non 1MB location, to extract better performance. (As we had discussions on mailing list some time back.)
In principle this is a limitation on boot-loaders part but as we can not fix the boot-loaders out there, probably we can try fixing it at kernel level.
What I have done here is that decompressor code will determine the final resting place of the kernel based on boot loader type. So if I have been loaded by kexec, I am supposed to run from loaded address otherwise I am supposed to run from CONFIG_PHYSICAL_START as I have been loaded at 1MB address due to boot loader limitation and that's not the intention.
A prototype patch is attached with the mail. I have assumed that I can assign a boot loader type id 9 to kexec (Documentation/i386/boot.txt). Also assuming that all other boot loaders apart from kexec have got 1MB limitation. If not, its trivial to include their boot loader ids also.
I have tested this patch and it works fine. What do you think about this approach ?
Thanks
Vivek
---
arch/i386/boot/compressed/head.S | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-)
arch/i386/boot/compressed/head.S renamed from arch/i386/boot/compressed/head.S~debug1-patch +30 -2
@@ -60,13 +60,32 @@ startup_32: * a relocatable kernel this is the delta to our load address otherwise * this is the delta to CONFIG_PHYSICAL start. */ + #ifdef CONFIG_RELOCTABLE + /* If loaded by non kexec boot loader, then we will be loaded + * at 1MB fixed address. But probably the intention is to run + * from a address for which kernel has been compiled which can + * be non 1MB. + */ + xorl %eax, %eax + movb 0x210(%esi), %al + + / * check boot loader type. Kexec bootloader id 9, version any */ + shrl $4, %eax + subl $0x9, %eax + jnz 1f + + /* Run kernel from the location it has been loaded at. */ movl %ebp, %ebx + jmp 2f + + /* Run the kernel from compiled destination location. */ +1: movl $(CONFIG_PHYSICAL_START - startup32), %ebx #else movl $(CONFIG_PHYSICAL_START - startup_32), %ebx #endif - /* Replace the compressed data size with the uncompressed size */ +2: /* Replace the compressed data size with the uncompressed size */ subl input_len(%ebp), %ebx movl output_len(%ebp), %eax addl %eax, %ebx
@@ -95,7 +114,16 @@ startup_32: /* Compute the kernel start address. */ #ifdef CONFIG_RELOCATABLE + xorl %eax, %eax + movb 0x210(%esi), %al + / * check boot loader type. Kexec bootloader id 9, version any */ + shrl $4, %eax + subl $0x9, %eax + jnz 3f leal startup_32(%ebp), %ebp + jmp 4f +3: + movl $CONFIG_PHYSICAL_START, %ebp #else movl $CONFIG_PHYSICAL_START, %ebp #endif
@@ -103,7 +131,7 @@ startup_32: /* * Jump to the relocated address. */ - leal relocated(%ebx), %eax +4: leal relocated(%ebx), %eax jmp *%eax .section ".text" relocated:
_
Quoted 10 lines · Vivek Goyal
Quoted 9 lines · Eric W. Biederman
The problem:
We can't always run the kernel at 1MB or 2MB, and so people who need different addresses must build multiple kernels. The bzImage format can't even represent loading a kernel at other than it's default address. With kexec on panic now starting to be used by distros having a kernel not running at the default load address is starting to become common.
Quoted 8 lines
Hi Eric,
There seems to be a small anomaly in the current set of patches for i386.
For example if one compiles the kernel with
CONFIG_RELOCATABLE=yandCONFIG_PHYSICAL_START=0x400000(4MB) and he uses grub to load the kernel then kernel would run from 1MB location. I think user would expect it to run from 4MB location.
Agreed. That is a non-intuitive, and should probably be fixed.
Quoted 17 lines
I think distro's might want to keep above config options enabled.
CONFIG_RELOCATABLE=yso that kexec can load kdump kernel at a different address andCONFIG_PHYSICAL_START=non1MB location, to extract better performance. (As we had discussions on mailing list some time back.)In principle this is a limitation on boot-loaders part but as we can not fix the boot-loaders out there, probably we can try fixing it at kernel level.
What I have done here is that decompressor code will determine the final resting place of the kernel based on boot loader type. So if I have been loaded by kexec, I am supposed to run from loaded address otherwise I am supposed to run from
CONFIG_PHYSICAL_STARTas I have been loaded at 1MB address due to boot loader limitation and that's not the intention.
Quoted 7 lines
A prototype patch is attached with the mail. I have assumed that I can assign a boot loader type id 9 to kexec (
Documentation/i386/boot.txt). Also assuming that all other boot loaders apart from kexec have got 1MB limitation. If not, its trivial to include their boot loader ids also.I have tested this patch and it works fine. What do you think about this approach ?
I think there is some value in it. But I need to digest it.
I have a cold right now and am running pretty weak, so it is going to take me a little bit to look at this.
I don't like taking action based upon bootloader type. As that assumes all kinds of things. But having better rules for when we perform relocation makes sense. There might be a way to detect coming from setup.S
I gave it some care last time, I worked through this and it didn't quite work.
I guess the practical question is do people see a real performance benefit when loading the kernel at 4MB?
Possibly the right solution is to do like I did on x86_64 and simply remove CONFIG_PHYSICAL_START, and always place the kernel at 4MB, or something like that.
The practical question is what to do to keep the complexity from spinning out of control. Removing CONFIG_PHYSICAL_START would seriously help with that.
Eric
Quoted 2 lines · Eric W. Biederman
I guess the practical question is do people see a real performance benefit when loading the kernel at 4MB?
Linus claimed lmbench saw some huge wins. Others showed that for eg, a kernel compile took the same amount of time, so take from that what you will..
Quoted 7 lines
Possibly the right solution is to do like I did on
x86_64and simply removeCONFIG_PHYSICAL_START, and always place the kernel at 4MB, or something like that.The practical question is what to do to keep the complexity from spinning out of control. Removing
CONFIG_PHYSICAL_STARTwould seriously help with that.
Given the two primary uses of that option right now are a) the aforementioned perf win and b) building kexec kernels, I doubt anyone would miss it once we go relocatable ;-)
Dave
Signature · 1 line
http://www.codemonkey.org.uk
Quoted 12 lines · Dave Jones
Quoted 2 lines · Eric W. Biederman
I guess the practical question is do people see a real performance benefit when loading the kernel at 4MB?
Linus claimed lmbench saw some huge wins. Others showed that for eg, a kernel compile took the same amount of time, so take from that what you will..
Quoted 4 lines
Possibly the right solution is to do like I did on
x86_64and simply removeCONFIG_PHYSICAL_START, and always place the kernel at 4MB, or something like that.
Quoted 8 lines
Quoted 3 lines
The practical question is what to do to keep the complexity from spinning out of control. Removing
CONFIG_PHYSICAL_STARTwould seriously help with that.Given the two primary uses of that option right now are a) the aforementioned perf win and b) building kexec kernels, I doubt anyone would miss it once we go relocatable ;-)
We DO want the performance gain with a conventional bootloader. The perf win is about the location of the uncompressed kernel, not the compressed kernel.
-hpa
Quoted 7 lines · H. Peter Anvin
Quoted 5 lines · Dave Jones
Quoted 2 lines · Eric W. Biederman
I guess the practical question is do people see a real performance benefit when loading the kernel at 4MB?
Linus claimed lmbench saw some huge wins. Others showed that for eg, a kernel compile took the same amount of time, so take from that what you
will..
But Linus wasn't comparing the same version of the kernel. So it was a bit unknown. Having someone reproduce those lm_bench numbers on the exact same kernel would be interesting.
Quoted 11 lines
Quoted 10 lines
Quoted 6 lines
Possibly the right solution is to do like I did on
x86_64and simply removeCONFIG_PHYSICAL_START, and always place the kernel at 4MB, or something like that.Quoted 1 line
The practical question is what to do to keep the complexity from spinning
out of control. Removing
CONFIG_PHYSICAL_STARTwould seriously help with that.Given the two primary uses of that option right now are a) the aforementioned perf win and b) building kexec kernels, I doubt anyone would miss it once we go relocatable ;-)
Quoted 2 lines
We DO want the performance gain with a conventional bootloader. The perf win is about the location of the uncompressed kernel, not the compressed kernel.
Agreed.
We also need a way to boot a kernel on an old machine with limited memory. Possibly we would only support this if PSE is not supported, which old machines don't support.
The complication that the decompressor must relocation the image for supporting old bootloaders is challenging in the context or a truly relocatable kernel, where we run at the address the bootloader put us.
The basic other concern is how flexible do we need to be with respect to relocation.
Eric
Quoted 14 lines · Eric W. Biederman
Quoted 12 lines · Vivek Goyal
Quoted 9 lines · Eric W. Biederman
The problem:
We can't always run the kernel at 1MB or 2MB, and so people who need different addresses must build multiple kernels. The bzImage format can't even represent loading a kernel at other than it's default address. With kexec on panic now starting to be used by distros having a kernel not running at the default load address is starting to become common.
Hi Eric,
Quoted 8 lines
Quoted 6 lines
There seems to be a small anomaly in the current set of patches for i386.
For example if one compiles the kernel with
CONFIG_RELOCATABLE=yandCONFIG_PHYSICAL_START=0x400000(4MB) and he uses grub to load the kernel then kernel would run from 1MB location. I think user would expect it to run from 4MB location.Agreed. That is a non-intuitive, and should probably be fixed.
I also agree that it is non-intitive. But I wonder if a cleaner fix would be to remove CONFIG_PHYSICAL_START all together. Isn't it just a work around for the kernel not being relocatable, or are there uses for it that relocation can't replace?
Signature · 3 lines
Horms H: http://www.vergenet.net/~horms/ W: http://www.valinux.co.jp/en/
Quoted 6 lines · Horms
I also agree that it is non-intitive. But I wonder if a cleaner fix would be to remove
CONFIG_PHYSICAL_STARTall together. Isn't it just a work around for the kernel not being relocatable, or are there uses for it that relocation can't replace?
Yes, booting with the 2^n existing bootloaders.
Relocation, as far as I've understood this patch, refers to loaded address, not runtime address.
-hpa
Quoted 8 lines · H. Peter Anvin
Quoted 6 lines · Horms
I also agree that it is non-intitive. But I wonder if a cleaner fix would be to remove
CONFIG_PHYSICAL_STARTall together. Isn't it just a work around for the kernel not being relocatable, or are there uses for it that relocation can't replace?
Quoted 4 lines
Yes, booting with the 2^n existing bootloaders.
Relocation, as far as I've understood this patch, refers to loaded address, not runtime address.
I believe Erics patch implements the following (correct me if I'm wrong):
vmlinux:
vmlinux is extended to contain relocation information. Absolute symbols are used for non-relocatable symbols, and section-relative symbols are used for relocatable symbols.
bzImage loader:
The bzImage loader code is no longer required to be loaded at a fixed address. The bzImage file contains vmlinux relocation information and the bzImage loader adjusts the relocations in vmlinux before executing it.
So I would say that the runtime address of symbols in vmlinux are changed by the bzImage loader. Or maybe I'm misunderstanding?
/ magnus
Quoted 8 lines · H. Peter Anvin
Quoted 5 lines · Horms
I also agree that it is non-intitive. But I wonder if a cleaner fix would be to remove
CONFIG_PHYSICAL_STARTall together. Isn't it just a work around for the kernel not being relocatable, or are there uses for it that relocation can't replace?Yes, booting with the 2^n existing bootloaders.
Which is something we certainly have to be careful with.
Quoted 2 lines
Relocation, as far as I've understood this patch, refers to loaded address, not runtime address.
Actually it refers to both.
Basically we detect if we were loaded with a clueless bootloader, aka at 1MB. If so we just load to whatever address the code was built to run at. Otherwise the code stays put.
To be loaded and run at a different address is what is needed for the crash dump scenario. Where we have to run at some reserved area of physical memory that the original kernel did not run from.
Eric
Quoted 9 lines · H. Peter Anvin
Quoted 6 lines · Horms
I also agree that it is non-intitive. But I wonder if a cleaner fix would be to remove
CONFIG_PHYSICAL_STARTall together. Isn't it just a work around for the kernel not being relocatable, or are there uses for it that relocation can't replace?Yes, booting with the 2^n existing bootloaders.
Ok, I must be confused then. I though CONFIG_PHYSICAL_START was introduced in order to allow an alternative address to be provided for kdump, and that previously it was hard-coded to some architecture-specific value.
What I was really getting as is if it needs to be configurable at compile time or not. Obviously there needs to be some sane default regardless.
Signature · 3 lines
Horms H: http://www.vergenet.net/~horms/ W: http://www.valinux.co.jp/en/
Quoted 11 lines · Horms
Quoted 9 lines · H. Peter Anvin
Quoted 6 lines · Horms
I also agree that it is non-intitive. But I wonder if a cleaner fix would be to remove
CONFIG_PHYSICAL_STARTall together. Isn't it just a work around for the kernel not being relocatable, or are there uses for it that relocation can't replace?Yes, booting with the 2^n existing bootloaders.
Quoted 8 lines
Ok, I must be confused then. I though
CONFIG_PHYSICAL_STARTwas introduced in order to allow an alternative address to be provided for kdump, and that previously it was hard-coded to some architecture-specific value.What I was really getting as is if it needs to be configurable at compile time or not. Obviously there needs to be some sane default regardless.
CONFIG_PHYSICAL_START has had 2 uses.
1) To allow a kernel to run a completely different address for use with kexec on panic.
2) To allow the kernel to be better aligned for better performance.
For maintenance reasons I propose we introduce CONFIG_PHYSICAL_ALIGN. Which will round our load address up to the nearest aligned address and run the kernel there. That is roughly what I am doing on x86_64 at this point.
s/CONFIG_PHYSICAL_START/CONFIG_PHYSICAL_ALIGN/ gives me well defined behavior and allows the alignment optimization without getting into weird semantics.
Before CONFIG_PHYSICAL_START we _always_ ran the arch/i386 kernel where it was loaded and I assumed we always would. Since people have realized better aligned kernels can run better this assumption became false. Going to CONFIG_PHYSICAL_ALIGN allows us to return to the simple assumption of always running the kernel where it is loaded modulo a little extra alignment.
Eric
Quoted 18 lines · Eric W. Biederman
Quoted 16 lines · Horms
Quoted 9 lines · H. Peter Anvin
Quoted 6 lines · Horms
I also agree that it is non-intitive. But I wonder if a cleaner fix would be to remove
CONFIG_PHYSICAL_STARTall together. Isn't it just a work around for the kernel not being relocatable, or are there uses for it that relocation can't replace?Yes, booting with the 2^n existing bootloaders.
Ok, I must be confused then. I though
CONFIG_PHYSICAL_STARTwas introduced in order to allow an alternative address to be provided for kdump, and that previously it was hard-coded to some architecture-specific value.
Quoted 8 lines
Quoted 3 lines
What I was really getting as is if it needs to be configurable at compile time or not. Obviously there needs to be some sane default regardless.
CONFIG_PHYSICAL_STARThas had 2 uses.
1) To allow a kernel to run a completely different address for use with kexec on panic.
2) To allow the kernel to be better aligned for better performance.
Thanks for making that clear
Quoted 9 lines
For maintenance reasons I propose we introduce
CONFIG_PHYSICAL_ALIGN. Which will round our load address up to the nearest aligned address and run the kernel there. That is roughly what I am doing onx86_64at this point.s/CONFIG_PHYSICAL_START/CONFIG_PHYSICAL_ALIGN/ gives me well defined behavior and allows the alignment optimization without getting into weird semantics.
Quoted 6 lines
Before
CONFIG_PHYSICAL_STARTwe _always_ ran thearch/i386kernel where it was loaded and I assumed we always would. Since people have realized better aligned kernels can run better this assumption became false. Going toCONFIG_PHYSICAL_ALIGNallows us to return to the simple assumption of always running the kernel where it is loaded modulo a little extra alignment.
That sounds reasonable to me. Though it is a little less flexible, do you think that could be a problem? Perhaps we could have both, though that would probably be quite confusing.
Signature · 3 lines
Horms H: http://www.vergenet.net/~horms/ W: http://www.valinux.co.jp/en/
Quoted 2 lines · Horms
Quoted 1 line · Eric W. Biederman
Horms <[email protected]> writes:
<snip>
Quoted 16 lines
Quoted 9 lines
For maintenance reasons I propose we introduce
CONFIG_PHYSICAL_ALIGN. Which will round our load address up to the nearest aligned address and run the kernel there. That is roughly what I am doing onx86_64at this point.s/CONFIG_PHYSICAL_START/CONFIG_PHYSICAL_ALIGN/ gives me well defined behavior and allows the alignment optimization without getting into weird semantics.
Quoted 6 lines
Before
CONFIG_PHYSICAL_STARTwe _always_ ran thearch/i386kernel where it was loaded and I assumed we always would. Since people have realized better aligned kernels can run better this assumption became false. Going toCONFIG_PHYSICAL_ALIGNallows us to return to the simple assumption of always running the kernel where it is loaded modulo a little extra alignment.
Quoted 3 lines
That sounds reasonable to me. Though it is a little less flexible, do you think that could be a problem? Perhaps we could have both, though that would probably be quite confusing.
More than reasonable. By changing this it seems that the kernel would still work with older bootloaders, function properly under kexec and might actually lead to a way to potentially recover a system from a crash without a reboot by allowing the kexec'd kernel to reset the system.
Of course the last is only a wish... Never happen because of the complexity involved. It would require a lot of work (I'd do this, but I'm currently arguing with the kernel over my attempts at building a functional DRM backed console) in having to switch back to real-mode to make the proper BIOS calls to reset the busses et. al. before switching *back* to kernel mode to run the standard startup.
Still, by letting a kernel run where it's loaded plus some modulo to get it properly aligned in memory solves several problems. It removes the need for CONFIG_PHYSICAL_START and the code involved in handling that. The kexec code that reserves memory for the new kernel image can be tweaked to always allocate the memory *aligned*...
Anyway, I'd better get back to the DRMCon code...
DRH
Quoted 36 lines · Eric W. Biederman
Quoted 11 lines · Horms
Quoted 9 lines · H. Peter Anvin
Quoted 6 lines · Horms
I also agree that it is non-intitive. But I wonder if a cleaner fix would be to remove
CONFIG_PHYSICAL_STARTall together. Isn't it just a work around for the kernel not being relocatable, or are there uses for it that relocation can't replace?Yes, booting with the 2^n existing bootloaders.
Quoted 8 lines
Ok, I must be confused then. I though
CONFIG_PHYSICAL_STARTwas introduced in order to allow an alternative address to be provided for kdump, and that previously it was hard-coded to some architecture-specific value.What I was really getting as is if it needs to be configurable at compile time or not. Obviously there needs to be some sane default regardless.
CONFIG_PHYSICAL_STARThas had 2 uses.
1) To allow a kernel to run a completely different address for use with kexec on panic.
2) To allow the kernel to be better aligned for better performance.For maintenance reasons I propose we introduce
CONFIG_PHYSICAL_ALIGN. Which will round our load address up to the nearest aligned address and run the kernel there. That is roughly what I am doing onx86_64at this point.s/CONFIG_PHYSICAL_START/CONFIG_PHYSICAL_ALIGN/ gives me well defined behavior and allows the alignment optimization without getting into weird semantics.
Quoted 7 lines
Before
CONFIG_PHYSICAL_STARTwe _always_ ran thearch/i386kernel where it was loaded and I assumed we always would. Since people have realized better aligned kernels can run better this assumption became false. Going toCONFIG_PHYSICAL_ALIGNallows us to return to the simple assumption of always running the kernel where it is loaded modulo a little extra alignment.
Hi Eric,
I have tried implementing your idea of replacing CONFIG_PHYSICAL_START with CONFIG_PHYSICAL_ALIGN. Please find attached the patch.
It applies on top of your relocatable kernel patch series.
I guess there should be a way for running kernel to tell user space that what's the offset of the addr at which kernel is running to the address for which kernel has been compiled. This info can be useful for debuggers in case they happen to debug the core of a kernel which was not running at compiled addr.
Thanks
Vivek
o Get rid of CONFIG_PHYSICAL_START and implement CONFIG_PHYSICAL_ALIGN
---
arch/i386/Kconfig | 34 ++++++++++++++++++---------------- arch/i386/boot/bootsect.S | 8 ++++---- arch/i386/boot/compressed/head.S | 28 ++++++++++++++++------------ arch/i386/boot/compressed/misc.c | 7 ++++--- arch/i386/boot/compressed/vmlinux.lds | 3 +++ arch/i386/kernel/vmlinux.lds.S | 5 +++-- include/asm-i386/boot.h | 6 +++++- 7 files changed, 53 insertions(+), 38 deletions(-)
arch/i386/Kconfig renamed from arch/i386/Kconfig~i386-implement-config-physical-align-option +18 -16
@@ -773,24 +773,26 @@ config RELOCATABLE must live at a different physical address than the primary kernel. -config PHYSICAL_START - hex "Physical address where the kernel is loaded" if (EMBEDDED || CRASH_DUMP) - - default "0x1000000" if CRASH_DUMP +config PHYSICAL_ALIGN + hex "Alignment value to which kernel should be aligned" if (EMBEDDED) default "0x100000" - range 0x100000 0x37c00000 + range 0x2000 0x400000 help - This gives the physical address where the kernel is loaded. Normally - for regular kernels this value is 0x100000 (1MB). But in the case - of kexec on panic the fail safe kernel needs to run at a different - address than the panic-ed kernel. This option is used to set the load - address for kernels used to capture crash dump on being kexec'ed - after panic. The default value for crash dump kernels is - 0x1000000 (16MB). This can also be set based on the "X" value as - specified in the "crashkernel=YM@XM" command line boot parameter - passed to the panic-ed kernel. Typically this parameter is set as - crashkernel=64M@16M. Please take a look at - Documentation/kdump/kdump.txt for more details about crash dumps. + This value puts the alignment restrictions on physical address + where kernel is loaded and run from. Kernel is compiled for an + address which meets above alignment restriction. + + If bootloader loads the kernel at a non-aligned address and + CONFIG_RELOCATABLE is set, kernel will move itself to nearest + address aligned to above value and run from there. + + If bootloader loads the kernel at a non-aligned address and + CONFIG_RELOCATABLE is not set, kernel will ignore the run time + load address and decompress itself to the address it has been + compiled for and run from there. The address for which kernel is + compiled already meets above alignment restrictions. Hence the + end result is that kernel runs from a physical address meeting above + alignment restrictions. Don't change this unless you know what you are doing.
include/asm-i386/boot.h renamed from include/asm-i386/boot.h~i386-implement-config-physical-align-option +5 -1
@@ -12,4 +12,8 @@#define EXTENDED_VGA 0xfffe/* 80x50 mode */ #define ASK_VGA 0xfffd/* ask for it at bootup */ -#endif +/* Physical address where kenrel should be loaded. */ +#define LOAD_PHYSICAL_ADDR ((0x100000 + CONFIG_PHYSICAL_ALIGN - 1) \ + & ~(CONFIG_PHYSICAL_ALIGN - 1)) + +#endif /* _LINUX_BOOT_H */
arch/i386/kernel/vmlinux.lds.S renamed from arch/i386/kernel/vmlinux.lds.S~i386-implement-config-physical-align-option +3 -2
@@ -2,13 +2,14 @@ * Written by Martin Mares <[email protected]>; */ -#define LOAD_OFFSET __PAGE_OFFSET +#define LOAD_OFFSET __PAGE_OFFSET #include <linux/config.h> #include <asm-generic/vmlinux.lds.h> #include <asm/thread_info.h> #include <asm/page.h> #include <asm/cache.h> +#include <asm/boot.h> OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386)
@@ -16,7 +17,7 @@ ENTRY(phys_startup_32) jiffies = jiffies_64; SECTIONS { - . = LOAD_OFFSET + CONFIG_PHYSICAL_START; + . = LOAD_OFFSET + LOAD_PHYSICAL_ADDR; phys_startup_32 = startup_32 - LOAD_OFFSET; /* read-only */ .text : AT(ADDR(.text) - LOAD_OFFSET) {
arch/i386/boot/bootsect.S renamed from arch/i386/boot/bootsect.S~i386-implement-config-physical-align-option +4 -4
@@ -69,7 +69,7 @@ ehdr: #endif .word EM_386 # e_machine .int 1 # e_version - .int CONFIG_PHYSICAL_START # e_entry + .int LOAD_PHYSICAL_ADDR # e_entry .int phdr - _start # e_phoff .int 0 # e_shoff .int 0 # e_flags
@@ -90,12 +90,12 @@ normalize: phdr: .int PT_LOAD # p_type .int (SETUPSECTS+1)*512 # p_offset - .int __PAGE_OFFSET + CONFIG_PHYSICAL_START # p_vaddr - .int CONFIG_PHYSICAL_START # p_paddr + .int LOAD_PHYSICAL_ADDR + __PAGE_OFFSET # p_vaddr + .int LOAD_PHYSICAL_ADDR # p_paddr .int SYSSIZE*16 # p_filesz .int 0 # p_memsz .int PF_R | PF_W | PF_X # p_flags - .int 4*1024*1024 # p_align + .int CONFIG_PHYSICAL_ALIGN # p_align e_phdr1: .int PT_NOTE # p_type
arch/i386/boot/compressed/vmlinux.lds renamed from arch/i386/boot/compressed/vmlinux.lds~i386-implement-config-physical-align-option +3 -0
@@ -3,6 +3,9 @@ OUTPUT_ARCH(i386) ENTRY(startup_32) SECTIONS { + /* Be careful parts of head.S assume startup_32 is at + * address 0. + */ . = 0 ; .text.head : { _head = . ;
arch/i386/boot/compressed/head.S renamed from arch/i386/boot/compressed/head.S~i386-implement-config-physical-align-option +16 -12
@@ -27,6 +27,7 @@ #include <linux/linkage.h> #include <asm/segment.h> #include <asm/page.h> +#include <asm/boot.h> .section ".text.head" .globl startup_32
@@ -53,17 +54,19 @@ startup_32: 1: popl %ebp subl $1b, %ebp -/* Compute the delta between where we were compiled to run at - * and where the code will actually run at. + +/* %ebp contains the address we are loaded at by the boot loader and %ebx + * contains the address where we should move the kernel image temporarily + * for safe in-place decompression. */ - /* Start with the delta to where the kernel will run at. If we are - * a relocatable kernel this is the delta to our load address otherwise - * this is the delta to CONFIG_PHYSICAL start. - */ + #ifdef CONFIG_RELOCTABLE - movl %ebp, %ebx + movl %ebp, %ebx + addl $(CONFIG_PHYSICAL_ALIGN - 1), %ebx + andl $(~(CONFIG_PHYSICAL_ALIGN - 1)), %ebx + #else - movl $(CONFIG_PHYSICAL_START - startup_32), %ebx + movl $LOAD_PHYSICAL_ADDR, %ebx #endif /* Replace the compressed data size with the uncompressed size */
@@ -95,9 +98,10 @@ startup_32: /* Compute the kernel start address. */ #ifdef CONFIG_RELOCATABLE - leal startup_32(%ebp), %ebp + addl $(CONFIG_PHYSICAL_ALIGN - 1), %ebp + andl $(~(CONFIG_PHYSICAL_ALIGN - 1)), %ebp #else - movl $CONFIG_PHYSICAL_START, %ebp + movl $LOAD_PHYSICAL_ADDR, %ebp #endif /*
@@ -151,8 +155,8 @@ relocated: * and where it was actually loaded. */ movl %ebp, %ebx - subl $CONFIG_PHYSICAL_START, %ebx - + subl $LOAD_PHYSICAL_ADDR, %ebx + jz 2f /* Nothing to be done if loaded at compiled addr. */ /* * Process relocations. */
arch/i386/boot/compressed/misc.c renamed from arch/i386/boot/compressed/misc.c~i386-implement-config-physical-align-option +4 -3
@@ -18,6 +18,7 @@#include <asm/io.h> #include <asm/setup.h> #include <asm/page.h> +#include <asm/boot.h> /* WARNING!! * This code is compiled with -fPIC and it is relocated dynamically
@@ -585,12 +586,12 @@ asmlinkage void decompress_kernel(void * insize = input_len; inptr =0 ; -if (((u32 )output -CONFIG_PHYSICAL_START ) &0x3fffff ) -error ("Destination address not 4M aligned" ); +if ((u32 )output & (CONFIG_PHYSICAL_ALIGN -1 )) +error ("Destination address not CONFIG_PHYSICAL_ALIGN aligned" );if (end > ((-__PAGE_OFFSET-(512 <<20 )-1 ) &0x7fffffff ))error ("Destination address too large" );#ifndef CONFIG_RELOCATABLE -if ((u32 )output !=CONFIG_PHYSICAL_START ) +if ((u32 )output !=LOAD_PHYSICAL_ADDR )error ("Wrong destination address" );#endif
_
Quoted 11 lines · Vivek Goyal
Signed-off-by Vivek Goyal <[email protected]>---
arch/i386/boot/compressed/head.S | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-)diff -puN
arch/i386/boot/compressed/head.S~debug1-patcharch/i386/boot/compressed/head.S
arch/i386/boot/compressed/head.S startup_32: · line 64
Quoted 5 lines
arch/i386/boot/compressed/head.S renamed from arch/i386/boot/compressed/head.S~debug1-patch +1
-0@@ -60,13 +60,32 @@ startup_32: * a relocatable kernel this is the delta to our load address otherwise * this is the delta to CONFIG_PHYSICAL start. */ + #ifdef CONFIG_RELOCTABLE
^^^^^^^^^
Vivek, did you mean CONFIG_RELOCATABLE ?
Thanks
Rachita
Quoted 12 lines
arch/i386/boot/compressed/head.S renamed from arch/i386/boot/compressed/head.S~debug1-patch +12
-0+ /* If loaded by non kexec boot loader, then we will be loaded + * at 1MB fixed address. But probably the intention is to run + * from a address for which kernel has been compiled which can + * be non 1MB. + */ + xorl %eax, %eax + movb 0x210(%esi), %al + + / * check boot loader type. Kexec bootloader id 9, version any */ + shrl $4, %eax + subl $0x9, %eax + jnz 1f
Quoted 18 lines · Rachita Kothiyal
Quoted 11 lines · Vivek Goyal
Signed-off-by Vivek Goyal <[email protected]>---
arch/i386/boot/compressed/head.S | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-)diff -puN
arch/i386/boot/compressed/head.S~debug1-patcharch/i386/boot/compressed/head.Sarch/i386/boot/compressed/head.S startup_32: · line 64
Quoted 5 lines
arch/i386/boot/compressed/head.S renamed from arch/i386/boot/compressed/head.S~debug1-patch +1
-0@@ -60,13 +60,32 @@ startup_32: * a relocatable kernel this is the delta to our load address otherwise * this is the delta to CONFIG_PHYSICAL start. */ + #ifdef CONFIG_RELOCTABLE^^^^^^^^^
Quoted 2 lines
Vivek, did you mean
CONFIG_RELOCATABLE?
Hi Rachita,
Thanks for catching this. Yes I meant CONFIG_RELOCATABLE.
Thanks
Vivek