Skip to contentSkip to conversation

ELF Relocatable x86 and x86_64 bzImages

RFC In review Eric W. Biederman 16 participants 105 messages Aug 1, 2006 – Nov 5, 2006

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

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

#1 lore raw

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
index 2d4f138..db0833b 100644
@@ -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
index db5a373..7cd3c22 100644
@@ -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
#2 lore raw

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

#3 lore raw

PATCH 2/33 i386: define __pa_symbol

In reply to Eric W. Biederman

On 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
index f5bf544..eceb7f5 100644
@@ -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
#4 lore raw

Re: [PATCH 2/33] i386: define __pa_symbol

Quoted 21 lines · Eric W. Biederman

On 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 +0 -0
index f5bf544..eceb7f5 100644

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

#5 lore raw

Re: [PATCH 2/33] i386: define __pa_symbol

Quoted 18 lines · Andi Kleen
Quoted 16 lines · Eric W. Biederman

On 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(-)
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
index f5bf544..eceb7f5 100644
@@ -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.

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

#6 lore raw

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_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.

No problem with that, just use HIDE_RELOC

-Andi

#7 lore raw

PATCH 3/33 i386 setup.c: Reserve kernel memory starting from _text

In reply to Eric W. Biederman

Currently 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
index f168220..f3a451a 100644
@@ -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
#8 lore raw

PATCH 4/33 i386: CONFIG_PHYSICAL_START cleanup

In reply to Eric W. Biederman

Defining __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
index b5893e4..8f28ecd 100644
@@ -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
index b2ccd54..905c37e 100644
@@ -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
index db0833b..8bcf0e1 100644
@@ -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
index eceb7f5..1af9f6b 100644
@@ -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
#9 lore raw

Re: [PATCH 4/33] i386: CONFIG_PHYSICAL_START cleanup

Quoted 19 lines · Eric W. Biederman

Defining __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 +0 -0
index b5893e4..8f28ecd 100644

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

#10 lore raw

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.S

Quoted 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

#11 lore raw

Re: [PATCH 4/33] i386: CONFIG_PHYSICAL_START cleanup

In reply to Sam Ravnborg
Quoted 24 lines · Sam Ravnborg
Quoted 7 lines · Eric W. Biederman

Defining __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.

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.S

Quoted 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

#12 lore raw

Re: [PATCH 4/33] i386: CONFIG_PHYSICAL_START cleanup

Quoted 10 lines

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.

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

#13 lore raw

PATCH 5/33 i386 Kconfig: Add a range definition to config PHYSICAL_START

In reply to Eric W. Biederman

The 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
index daa75ce..062fa01 100644
@@ -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
#14 lore raw

PATCH 6/33 Make linux/elf.h safe to be included in assembly files

In reply to Eric W. Biederman

The 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
index b70d1d2..c5bf043 100644
@@ -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
#15 lore raw

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
index c5bf043..6fa8d3d 100644
@@ -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
#16 lore raw

PATCH 8/33 kallsyms.c: Generate relocatable symbols.

In reply to Eric W. Biederman

Print 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
index 22d281c..4c1ad0a 100644
@@ -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
#17 lore raw

Re: [PATCH 8/33] kallsyms.c: Generate relocatable symbols.

Quoted 7 lines · Eric W. Biederman

Print 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 static void write_src(void) · line 284

Quoted 9 lines
scripts/kallsyms.c +6 -1
 	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);
+		}

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."
#18 lore raw

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 _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 static void write_src(void) · line 284

Quoted 9 lines
scripts/kallsyms.c +6 -1
 	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);
+		}

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

#19 lore raw

PATCH 9/33 i386 boot: Add serial output support to the decompressor

In reply to Eric W. Biederman

This 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
index 905c37e..fcaa9f0 100644
@@ -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 0xA33F
 
 extern 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 vo
 	return 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
#20 lore raw

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 vo
 	return 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

#21 lore raw

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_printk instead 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

#22 lore raw

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.c

Maybe. Size is fairly important

Why is size important here?

-Andi

#23 lore raw

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.c

Maybe. 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

#24 lore raw

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.c

Maybe. 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.c and arch/x86_64/kernel/early_printk.c is that it is significant change in how the code of misc.c is 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

#25 lore raw

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

#26 lore raw

Re: [PATCH 9/33] i386 boot: Add serial output support to the decompressor

In reply to Andi Kleen
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_printk instead 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

#27 lore raw

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

Would surprise me.

-Andi

#28 lore raw

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_printk is 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.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.

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

#29 lore raw

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

#30 lore raw

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

#31 lore raw

PATCH 10/33 i386: Relocatable kernel support.

In reply to Eric W. Biederman

This 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
index 062fa01..a0707d7 100644
@@ -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
index 3e4adb1..e9d6eac 100644
@@ -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
index 258ea95..1c486d1 100644
@@ -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
new file mode 100644
index 0000000..973a23e
@@ -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
index 1ed9d79..707a88f 100644
@@ -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
index d2b684c..04b6ea8 100644
@@ -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
index 2925e66..b02308e 100644
@@ -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
#32 lore raw

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

#33 lore raw

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

#34 lore raw

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

#35 lore raw

Re: [PATCH 10/33] i386: Relocatable kernel support.

In reply to Eric W. Biederman
Quoted 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 -0
 	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 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

#36 lore raw

PATCH 11/33 i386 boot: Add an ELF header to bzImage

In reply to Eric W. Biederman

Increasingly 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
index e979466..44ef35c 100644
@@ -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
new file mode 100644
index 0000000..09301e5
@@ -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
#37 lore raw

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

#38 lore raw

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
+.endm

This 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

#39 lore raw

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
index e56c2ad..61f029f 100644
@@ -205,8 +205,8 @@ unsigned long __init e820_end_of_ram(voi
 		if (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
#40 lore raw

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
index 61f029f..56dd525 100644
@@ -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
#41 lore raw

PATCH 14/33 x86_64: Properly report in /proc/iomem the kernel address

In reply to Eric W. Biederman

The 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
index 8a099ff..11d31ea 100644
@@ -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
#42 lore raw

PATCH 15/33 x86_64: Fix kernel direct mapping size check

In reply to Eric W. Biederman

Instead 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
index 36647ce..454498c 100644
@@ -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
#43 lore raw

PATCH 16/33 x86_64: Assembly safe page.h and pgtable.h

In reply to Eric W. Biederman

This 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
new file mode 100644
index 0000000..54fb08f
@@ -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
index 10f3461..f030260 100644
@@ -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
index a31ab4e..211a2ca 100644
@@ -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
#44 lore raw

PATCH 17/33 x86_64: Separate normal memory map initialization from the hotplug case

In reply to Eric W. Biederman

Currently 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
index d14fb2d..0522c1c 100644
@@ -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(in
 	return 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 long 
 		unsigned 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(unsig
 		pgd_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)
-		asm volatile("movq %%cr4,%0" : "=r" (mmu_cr4_features));
+	asm volatile("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
#45 lore raw

PATCH 18/33 x86_64: Kill temp_boot_pmds

In reply to Eric W. Biederman

Early 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
index 6df05e6..ca57a37 100644
@@ -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
#46 lore raw

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_ioreamp and early_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_mapping is that find_early_table_space always finds pages below 1M.

I fixed this some time ago - obsolete comment?

-Andi

#47 lore raw

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_ioreamp and early_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_mapping is that find_early_table_space always 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

#48 lore raw

Re: [PATCH 18/33] x86_64: Kill temp_boot_pmds II

In reply to Eric W. Biederman
Quoted 5 lines · Eric W. Biederman

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.

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

#49 lore raw

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_ioreamp and early_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 file arch/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

#50 lore raw

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.c before 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

#51 lore raw

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.c before 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.

Ok. I will take a look.

Having any patches merged on a simple request for comments was a bit of a surprise :)

Eric

#52 lore raw

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
index ca57a37..a9e34d9 100644
@@ -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
index 211a2ca..5528e8b 100644
@@ -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
#53 lore raw

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
index 140051e..d2b4cfb 100644
@@ -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
#54 lore raw

PATCH 21/33 x86_64: modify copy_bootdata to use virtual addresses

In reply to Eric W. Biederman

Use 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
index 454498c..defef4e 100644
@@ -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           0x22
 
 extern 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 * r
  		cpu_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
#55 lore raw

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
index 23a03eb..c79b99a 100644
@@ -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
#56 lore raw

Re: [PATCH 22/33] x86_64: Fix gdt table size in trampoline.S

Makes sense, thanks. I queued the patch.

-Andi

#57 lore raw

PATCH 23/33 x86_64: cleanup segments

In reply to Eric W. Biederman

Move __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
index a9e34d9..d0e626e 100644
@@ -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
index d4bed33..58d6715 100644
@@ -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
#58 lore raw

PATCH 24/33 x86_64: Add EFER to the set registers saved by save_processor_state

In reply to Eric W. Biederman

EFER 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
index 91f7e67..fe865ea 100644
@@ -33,7 +33,6 @@ void __save_processor_state(struct saved
 	asm volatile ("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);
 	asm volatile ("movq %%cr0, %0" : "=r" (ctxt->cr0));
 	asm volatile ("movq %%cr2, %0" : "=r" (ctxt->cr2));
 	asm volatile ("movq %%cr3, %0" : "=r" (ctxt->cr3));
@@ -75,6 +75,7 @@ void __restore_processor_state(struct sa
 	/*
 	 * control registers
 	 */
+	wrmsrl(MSR_EFER, ctxt->efer);
 	asm volatile ("movq %0, %%cr8" :: "r" (ctxt->cr8));
 	asm volatile ("movq %0, %%cr4" :: "r" (ctxt->cr4));
 	asm volatile ("movq %0, %%cr3" :: "r" (ctxt->cr3));
include/asm-x86_64/suspend.h +1 -0
index bc7f817..a42306c 100644
@@ -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
#59 lore raw

PATCH 25/33 x86_64: 64bit PIC SMP trampoline

In reply to Eric W. Biederman

This 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
index d0e626e..8d1b4a7 100644
@@ -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
index 11d31ea..66816ba 100644
@@ -611,15 +611,8 @@ #endif
 		reserve_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
#60 lore raw

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

#61 lore raw

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
index 5ebf62c..d9b28f8 100644
@@ -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
index 8d1b4a7..a624586 100644
@@ -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
index a42306c..9c3f8de 100644
@@ -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
#62 lore raw

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

#63 lore raw

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
index 66816ba..21840ca 100644
@@ -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
#64 lore raw

PATCH 28/33 x86_64: Remove the identity mapping as early as possible.

In reply to 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.

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
index a624586..b0b5618 100644
@@ -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
index defef4e..99d4463 100644
@@ -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 * r
 	char *s;
 	int i;
 
+	/* Make NULL pointers segfault */
+	zap_identity_mappings();
 	for (i = 0; i < 256; i++)
 		set_intr_gate(i, early_idt_handler);
 	asm volatile("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));
-	asm volatile("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
index 21840ca..7225f61 100644
@@ -568,8 +568,6 @@ #endif
 
 	dmi_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
index 6fe58a6..a1f3aed 100644
@@ -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
index b46566a..149f363 100644
@@ -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
-		 */
-		asm volatile("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
index 5528e8b..d0816fb 100644
@@ -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
index 038fe1f..978ea43 100644
@@ -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
#65 lore raw

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

#66 lore raw

PATCH 29/33 x86_64: __pa and __pa_symbol address space separation

In reply to Eric W. Biederman

Currently __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
index 28ab806..e573263 100644
@@ -347,8 +347,8 @@ void __init alternative_instructions(voi
 	if (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
index 89e8486..8dbbb09 100644
@@ -750,10 +750,11 @@ void free_init_pages(char *what, unsigne
 	unsigned 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, unsigne
 void 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
index 7225f61..44a40e6 100644
@@ -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
index 5a1c0a3..5a54066 100644
@@ -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
index f603037..2e48407 100644
@@ -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_ta
 		return 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
index 149f363..5db93b9 100644
@@ -663,11 +663,11 @@ void free_init_pages(char *what, unsigne
 
 	printk(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
index 2685b1f..9d6196d 100644
@@ -51,7 +51,6 @@ static struct page *split_large_page(uns
 	SetPagePrivate(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 address
 			struct 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 address
 
 	if (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 long 
 			break; 
 		/* 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
index f030260..37f95ca 100644
@@ -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
index d0816fb..fa43712 100644
@@ -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
#67 lore raw

PATCH 30/33 x86_64: Remove CONFIG_PHYSICAL_START

In reply to Eric W. Biederman

I 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
index 28df7d8..763b25b 100644
@@ -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
index 6f55565..cf55d09 100644
@@ -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
index 3755b2e..259bb05 100644
@@ -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
index 840d5d9..06cf378 100644
@@ -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
index 7c4de31..741487b 100644
@@ -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
index ac8ea66..26d315b 100644
@@ -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
index 37f95ca..deed41a 100644
@@ -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
#68 lore raw

PATCH 31/33 x86_64 boot: Add serial output support to the decompressor

In reply to Eric W. Biederman

This 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
index f89d96f..8987c97 100644
@@ -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
#69 lore raw

PATCH 32/33 x86_64: Relocatable kernel support

In reply to Eric W. Biederman

This 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
index 8987c97..3dda50c 100644
@@ -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
index 1ed9d79..48117cf 100644
@@ -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
index 741487b..456fe8e 100644
@@ -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
index deed41a..d125c09 100644
@@ -61,6 +61,8 @@ #define PTE_MASK	PHYSICAL_PAGE_MASK
 
 typedef 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
#70 lore raw

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

#71 lore raw

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

#72 lore raw

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

#73 lore raw

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_32 for vmlinux but keep startup_32 for 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

#74 lore raw

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      8
#75 lore raw

PATCH 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
index deb063e..80a7492 100644
@@ -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
#76 lore raw
In reply to Eric W. Biederman
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 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.

Quoted 4 lines

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.

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

#77 lore raw

On Tue, 01 Aug 2006 21:26:28 +0200, Vivek Goyal wrote:
...

Quoted 4 lines

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.

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

#78 lore raw
In reply to Vivek Goyal
Quoted 11 lines · Vivek Goyal

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.

I don't think this is practical given the virtual space constraints on i386 systems.

-hpa

#79 lore raw
Quoted 10 lines · H. Peter Anvin
Quoted 8 lines · Vivek Goyal

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.

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

#80 lore raw
In reply to Eric W. Biederman
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/i386 kernel.

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

#81 lore raw
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/i386 kernel.

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

#82 lore raw
In reply to Eric W. Biederman
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

#83 lore raw
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

#84 lore raw
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.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.

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

#85 lore raw
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.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.

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

#86 lore raw
In reply to Eric W. Biederman
Quoted 3 lines

There is one outstanding issue where I am probably requiring too much alignment on the arch/i386 kernel.

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

#87 lore raw
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/i386 kernel.

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

#88 lore raw
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/i386 kernel.

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

#89 lore raw
In reply to Eric W. Biederman
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
diff -puN arch/i386/boot/compressed/head.S~debug1-patch arch/i386/boot/compressed/head.S
@@ -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:

_

#90 lore raw
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=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.

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=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.

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

#91 lore raw
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_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.

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
#92 lore raw
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_64 and simply remove CONFIG_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_START would 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

#93 lore raw
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_64 and simply remove CONFIG_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_START would 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

#94 lore raw
In reply to Eric W. Biederman
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=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.

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/
#95 lore raw
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_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?

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

#96 lore raw
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_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?

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

#97 lore raw
In reply to H. Peter Anvin
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_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?

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

#98 lore raw
In reply to H. Peter Anvin
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_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?

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/
#99 lore raw
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_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?

Yes, booting with the 2^n existing bootloaders.

Quoted 8 lines

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.

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

#100 lore raw
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_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?

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.

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_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.

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

Quoted 6 lines

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.

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/
#101 lore raw
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 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.

Quoted 6 lines

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.

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

#102 lore raw
In reply to Eric W. Biederman
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_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?

Yes, booting with the 2^n existing bootloaders.

Quoted 8 lines

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.

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.

Quoted 7 lines

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.

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
diff -puN arch/i386/Kconfig~i386-implement-config-physical-align-option arch/i386/Kconfig
@@ -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
diff -puN include/asm-i386/boot.h~i386-implement-config-physical-align-option include/asm-i386/boot.h
@@ -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
diff -puN arch/i386/kernel/vmlinux.lds.S~i386-implement-config-physical-align-option arch/i386/kernel/vmlinux.lds.S
@@ -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
diff -puN arch/i386/boot/bootsect.S~i386-implement-config-physical-align-option arch/i386/boot/bootsect.S
@@ -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
diff -puN arch/i386/boot/compressed/vmlinux.lds~i386-implement-config-physical-align-option arch/i386/boot/compressed/vmlinux.lds
@@ -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
diff -puN arch/i386/boot/compressed/head.S~i386-implement-config-physical-align-option arch/i386/boot/compressed/head.S
@@ -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
diff -puN arch/i386/boot/compressed/misc.c~i386-implement-config-physical-align-option arch/i386/boot/compressed/misc.c
@@ -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
 

_

#103 lore raw
In reply to Vivek Goyal
Quoted 11 lines · Vivek Goyal

---

 arch/i386/boot/compressed/head.S |   32 ++++++++++++++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)

diff -puN arch/i386/boot/compressed/head.S~debug1-patch arch/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
#104 lore raw
Quoted 18 lines · Rachita Kothiyal
Quoted 11 lines · Vivek Goyal

---

 arch/i386/boot/compressed/head.S |   32 ++++++++++++++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)

diff -puN arch/i386/boot/compressed/head.S~debug1-patch arch/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
              ^^^^^^^^^
Quoted 2 lines

Vivek, did you mean CONFIG_RELOCATABLE ?

Hi Rachita,

Thanks for catching this. Yes I meant CONFIG_RELOCATABLE.

Thanks
Vivek