Skip to contentSkip to conversation

kexec: put bzImage and ramdisk above 4G for x86 64bit

PATCH Superseded Yinghai Lu 4 participants 25 messages Nov 21, 2012 – Nov 22, 2012

Subsystems (3)

v3 of 9 Superseded Latest is v9 →

lore
Share & tools
lore

Yinghai Lu

author
#0 lore raw

v3 cover kexec: put bzImage and ramdisk above 4G for x86 64bit

Now we have limit kdump reserved under 896M, because kexec has the limitation. and also bzImage need to stay under 4g.

kernel parts changes could be found at:
git://git.kernel.org/pub/scm/linux/kernel/git/yinghai/linux-yinghai.git for-x86-boot

here patches are for kexec tools to load bzImage and ramdisk high acccording to new added boot header fields.

-v3: address review from Eric to use locate_hole at first.
use xloadflags instead.

Yinghai Lu (4):
kexec, x86: add boot header member for version 2.12 kexec, x86: put ramdisk high for 64bit bzImage kexec, x86: set ext_cmd_line_ptr when boot_param is above 4g kexec, x86_64: Load bzImage64 above 4G

 include/x86/x86-linux.h             |   26 +++-
 kexec/arch/i386/x86-linux-setup.c   |   25 +++-
 kexec/arch/x86_64/Makefile          |    1 +
 kexec/arch/x86_64/kexec-bzImage64.c |  327 +++++++++++++++++++++++++++++++++++
 kexec/arch/x86_64/kexec-x86_64.c    |    1 +
 kexec/arch/x86_64/kexec-x86_64.h    |    5 +
 6 files changed, 378 insertions(+), 7 deletions(-)
 create mode 100644 kexec/arch/x86_64/kexec-bzImage64.c
Signature · 7 lines
1.7.7


_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec
author
#1 lore raw

PATCH v3 1/4 kexec, x86: add boot header member for version 2.12

will use ext_ramdisk_image/size, and xloadflags to put ramdisk and bzImage high for 64bit.

---
 include/x86/x86-linux.h |   26 +++++++++++++++++++++++---
 1 files changed, 23 insertions(+), 3 deletions(-)
include/x86/x86-linux.h +23 -3
index 27af02b..6d6c5e0 100644
@@ -174,11 +174,21 @@ struct x86_linux_param_header {
 	/* 2.04+ */
 	uint32_t kernel_alignment;		/* 0x230 */
 	uint8_t  relocatable_kernel;		/* 0x234 */
-	uint8_t  reserved15[3];			/* 0x235 */
+	uint8_t  min_alignment;			/* 0x235 */
+	uint16_t xloadflags;			/* 0x236 */
 	uint32_t cmdline_size;			/* 0x238 */
 	uint32_t hardware_subarch;		/* 0x23C */
 	uint64_t hardware_subarch_data;		/* 0x240 */
-	uint8_t  reserved16[0x290 - 0x248];	/* 0x248 */
+	uint32_t payload_offset;		/* 0x248 */
+	uint32_t payload_length;		/* 0x24C */
+	uint64_t setup_data;			/* 0x250 */
+	uint64_t pref_address;			/* 0x258 */
+	uint32_t init_size;			/* 0x260 */
+	uint32_t handover_offset;		/* 0x264 */
+	uint32_t ext_ramdisk_image;		/* 0x268 */
+	uint32_t ext_ramdisk_size;		/* 0x26C */
+	uint32_t ext_cmd_line_ptr;		/* 0x270 */
+	uint8_t  reserved16[0x290 - 0x274];	/* 0x274 */
 	uint32_t edd_mbr_sig_buffer[EDD_MBR_SIG_MAX];	/* 0x290 */
 #endif
 	struct 	e820entry e820_map[E820MAX];	/* 0x2d0 */
@@ -241,10 +251,20 @@ struct x86_linux_header {
 #else
 	uint32_t kernel_alignment;		/* 0x230 */
 	uint8_t  relocatable_kernel;		/* 0x234 */
-	uint8_t  reserved6[3];			/* 0x235 */
+	uint8_t  min_alignment;			/* 0x235 */
+	uint16_t xloadflags;			/* 0x236 */
 	uint32_t cmdline_size;                  /* 0x238 */
 	uint32_t hardware_subarch;              /* 0x23C */
 	uint64_t hardware_subarch_data;         /* 0x240 */
+	uint32_t payload_offset;		/* 0x248 */
+	uint32_t payload_length;		/* 0x24C */
+	uint64_t setup_data;			/* 0x250 */
+	uint64_t pref_address;			/* 0x258 */
+	uint32_t init_size;			/* 0x260 */
+	uint32_t handover_offset;		/* 0x264 */
+	uint32_t ext_ramdisk_image;		/* 0x268 */
+	uint32_t ext_ramdisk_size;		/* 0x26C */
+	uint32_t ext_cmd_line_ptr;		/* 0x270 */
 #endif
 } PACKED;
 
Signature · 7 lines
1.7.7


_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec
author
#2 lore raw

PATCH v3 2/4 kexec, x86: put ramdisk high for 64bit bzImage

In reply to Yinghai Lu

We could put ramdisk high for bzImage on 64bit for protocol 2.12.

-v2: change ext_... handling to way that eric like.

---
 kexec/arch/i386/x86-linux-setup.c |   18 +++++++++++++++---
 1 files changed, 15 insertions(+), 3 deletions(-)
kexec/arch/i386/x86-linux-setup.c +15 -3
index b7ab8ea..3c31f64 100644
@@ -64,7 +64,11 @@ void setup_linux_bootloader_parameters(
 	/* Find the maximum initial ramdisk address */
 	initrd_addr_max = DEFAULT_INITRD_ADDR_MAX;
 	if (real_mode->protocol_version >= 0x0203) {
-		initrd_addr_max = real_mode->initrd_addr_max;
+		if (real_mode->protocol_version >= 0x020c &&
+		    real_mode->xloadflags & 1)
+			initrd_addr_max = ULONG_MAX;
+		else
+			initrd_addr_max = real_mode->initrd_addr_max;
 		dbgprintf("initrd_addr_max is 0x%lx\n", initrd_addr_max);
 	}
 
@@ -81,8 +85,16 @@ void setup_linux_bootloader_parameters(
 	}
 
 	/* Ramdisk address and size */
-	real_mode->initrd_start = initrd_base;
-	real_mode->initrd_size  = initrd_size;
+	real_mode->initrd_start = initrd_base & 0xffffffffUL;
+	real_mode->initrd_size  = initrd_size & 0xffffffffUL;
+
+	if (real_mode->protocol_version >= 0x020c &&
+	    (initrd_base & 0xffffffffUL) != initrd_base)
+		real_mode->ext_ramdisk_image = initrd_base >> 32;
+
+	if (real_mode->protocol_version >= 0x020c &&
+	    (initrd_size & 0xffffffffUL) != initrd_size)
+		real_mode->ext_ramdisk_size = initrd_size >> 32;
 
 	/* The location of the command line */
 	/* if (real_mode_base == 0x90000) { */
Signature · 7 lines
1.7.7


_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec
author
#3 lore raw

PATCH v3 3/4 kexec, x86: set ext_cmd_line_ptr when boot_param is above 4g

In reply to Yinghai Lu

update ext_cmd_line_ptr for bzImage from protocal 2.12 that could have command line above 4g.

-v2: update ext_... handling to the way that Eric likes.

---
 kexec/arch/i386/x86-linux-setup.c |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletions(-)
kexec/arch/i386/x86-linux-setup.c +6 -1
index 3c31f64..d12dab1 100644
@@ -103,7 +103,12 @@ void setup_linux_bootloader_parameters(
 		/* setup_move_size */
 	/* } */
 	if (real_mode->protocol_version >= 0x0202) {
-		real_mode->cmd_line_ptr = real_mode_base + cmdline_offset;
+		unsigned long cmd_line_ptr = real_mode_base + cmdline_offset;
+
+		real_mode->cmd_line_ptr = cmd_line_ptr & 0xffffffffUL;
+		if ((real_mode->protocol_version >= 0x020c) &&
+		    ((cmd_line_ptr & 0xffffffffUL) != cmd_line_ptr))
+			real_mode->ext_cmd_line_ptr = cmd_line_ptr >> 32;
 	}
 
 	/* Fill in the command line */
Signature · 7 lines
1.7.7


_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec
author
#4 lore raw

PATCH v3 4/4 kexec, x86_64: Load bzImage64 above 4G

In reply to Yinghai Lu

need to check xloadflags to see the bzImage is for 64bit relocatable.

-v2: add kexec-bzImage64.c according to Eric.
-v3: don't need to purgatory under 2g after Eric's change to purgatory code. -v4: use locate_hole find position first then add_buffer... suggested by Eric
add buffer for kernel image at last to make kexec-load faster. use xloadflags in setup_header to tell if is bzImage64.

---
 kexec/arch/x86_64/Makefile          |    1 +
 kexec/arch/x86_64/kexec-bzImage64.c |  327 +++++++++++++++++++++++++++++++++++
 kexec/arch/x86_64/kexec-x86_64.c    |    1 +
 kexec/arch/x86_64/kexec-x86_64.h    |    5 +
 4 files changed, 334 insertions(+), 0 deletions(-)
 create mode 100644 kexec/arch/x86_64/kexec-bzImage64.c
kexec/arch/x86_64/Makefile +1 -0
index 405bdf5..1cf10f9 100644
@@ -13,6 +13,7 @@ x86_64_KEXEC_SRCS += kexec/arch/i386/crashdump-x86.c
 x86_64_KEXEC_SRCS_native =  kexec/arch/x86_64/kexec-x86_64.c
 x86_64_KEXEC_SRCS_native += kexec/arch/x86_64/kexec-elf-x86_64.c
 x86_64_KEXEC_SRCS_native += kexec/arch/x86_64/kexec-elf-rel-x86_64.c
+x86_64_KEXEC_SRCS_native += kexec/arch/x86_64/kexec-bzImage64.c
 
 x86_64_KEXEC_SRCS += $(x86_64_KEXEC_SRCS_native)
 
kexec/arch/x86_64/kexec-bzImage64.c new file +327 -0

327 lines not on this page · raw message

kexec/arch/x86_64/kexec-x86_64.c +1 -0
index 6c42c32..5c23e01 100644
@@ -37,6 +37,7 @@ struct file_type file_type[] = {
 	{ "multiboot-x86", multiboot_x86_probe, multiboot_x86_load,
 	  multiboot_x86_usage },
 	{ "elf-x86", elf_x86_probe, elf_x86_load, elf_x86_usage },
+	{ "bzImage64", bzImage64_probe, bzImage64_load, bzImage64_usage },
 	{ "bzImage", bzImage_probe, bzImage_load, bzImage_usage },
 	{ "beoboot-x86", beoboot_probe, beoboot_load, beoboot_usage },
 	{ "nbi-x86", nbi_probe, nbi_load, nbi_usage },
kexec/arch/x86_64/kexec-x86_64.h +5 -0
index a97cd71..b820ae8 100644
@@ -28,4 +28,9 @@ int elf_x86_64_load(int argc, char **argv, const char *buf, off_t len,
 	struct kexec_info *info);
 void elf_x86_64_usage(void);
 
+int bzImage64_probe(const char *buf, off_t len);
+int bzImage64_load(int argc, char **argv, const char *buf, off_t len,
+        struct kexec_info *info);
+void bzImage64_usage(void);
+
 #endif /* KEXEC_X86_64_H */
Signature · 7 lines
1.7.7


_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec
#5 lore raw

Re: [PATCH v3 4/4] kexec, x86_64: Load bzImage64 above 4G

On Tue, Nov 20, 2012 at 11:31:38PM -0800, Yinghai Lu wrote:

[..]

kexec/arch/x86_64/kexec-bzImage64.c line 238

Quoted 13 lines
kexec/arch/x86_64/kexec-bzImage64.c new file +13 -0
+	/* avoid cross GB boundary */
+	align = real_mode->kernel_alignment;
+	addr = locate_hole(info, size, align, 0x100000, -1, -1);
+	if (addr == ULONG_MAX)
+		die("can not load bzImage64");
+	/* same GB ? */
+	while ((addr >> 30) != ((addr + size - 1) >> 30)) {
+		addr = locate_hole(info, size, align, 0x100000,
+				 round_down(addr + size - 1, (1UL<<30)), -1);
+		if (addr == ULONG_MAX)
+			die("can not load bzImage64");
+	}
+	dbgprintf("Found kernel buffer at %lx size %lx\n", addr, size);

Where does this limitation of not loading kernel across GB boundary come from?

Vivek

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#6 lore raw

Re: [PATCH v3 4/4] kexec, x86_64: Load bzImage64 above 4G

Quoted 20 lines · Vivek Goyal

On Tue, Nov 20, 2012 at 11:31:38PM -0800, Yinghai Lu wrote:

[..]

kexec/arch/x86_64/kexec-bzImage64.c line 238

Quoted 13 lines
kexec/arch/x86_64/kexec-bzImage64.c new file +13 -0
+	/* avoid cross GB boundary */
+	align = real_mode->kernel_alignment;
+	addr = locate_hole(info, size, align, 0x100000, -1, -1);
+	if (addr == ULONG_MAX)
+		die("can not load bzImage64");
+	/* same GB ? */
+	while ((addr >> 30) != ((addr + size - 1) >> 30)) {
+		addr = locate_hole(info, size, align, 0x100000,
+				 round_down(addr + size - 1, (1UL<<30)), -1);
+		if (addr == ULONG_MAX)
+			die("can not load bzImage64");
+	}
+	dbgprintf("Found kernel buffer at %lx size %lx\n", addr, size);

Where does this limitation of not loading kernel across GB boundary come from?

Seriously... that is bizarre.

-hpa

Signature · 8 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.


_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec
author
#7 lore raw

Re: [PATCH v3 4/4] kexec, x86_64: Load bzImage64 above 4G

In reply to Vivek Goyal
Quoted 17 lines · Vivek Goyal

On Tue, Nov 20, 2012 at 11:31:38PM -0800, Yinghai Lu wrote:

[..]

kexec/arch/x86_64/kexec-bzImage64.c line 238

Quoted 13 lines
kexec/arch/x86_64/kexec-bzImage64.c new file +13 -0
+     /* avoid cross GB boundary */
+     align = real_mode->kernel_alignment;
+     addr = locate_hole(info, size, align, 0x100000, -1, -1);
+     if (addr == ULONG_MAX)
+             die("can not load bzImage64");
+     /* same GB ? */
+     while ((addr >> 30) != ((addr + size - 1) >> 30)) {
+             addr = locate_hole(info, size, align, 0x100000,
+                              round_down(addr + size - 1, (1UL<<30)), -1);
+             if (addr == ULONG_MAX)
+                     die("can not load bzImage64");
+     }
+     dbgprintf("Found kernel buffer at %lx size %lx\n", addr, size);
Quoted 2 lines

Where does this limitation of not loading kernel across GB boundary come from?

in kernel arch/x86/kernel/head_64.S

it only set first 1G ident mapping. and if it find that code is above 1G, it will set extra ident mapping
for new _text.._end.
To make checking and add extra mapping simple and also save two extra pages for mapping.
Limit that _text.._end in them same GB range.

Thanks

Yinghai

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#8 lore raw

Re: [PATCH v3 4/4] kexec, x86_64: Load bzImage64 above 4G

Quoted 21 lines · Yinghai Lu
Quoted 17 lines · Vivek Goyal

On Tue, Nov 20, 2012 at 11:31:38PM -0800, Yinghai Lu wrote:

[..]

kexec/arch/x86_64/kexec-bzImage64.c line 238

Quoted 13 lines
kexec/arch/x86_64/kexec-bzImage64.c new file +13 -0
+     /* avoid cross GB boundary */
+     align = real_mode->kernel_alignment;
+     addr = locate_hole(info, size, align, 0x100000, -1, -1);
+     if (addr == ULONG_MAX)
+             die("can not load bzImage64");
+     /* same GB ? */
+     while ((addr >> 30) != ((addr + size - 1) >> 30)) {
+             addr = locate_hole(info, size, align, 0x100000,
+                              round_down(addr + size - 1, (1UL<<30)), -1);
+             if (addr == ULONG_MAX)
+                     die("can not load bzImage64");
+     }
+     dbgprintf("Found kernel buffer at %lx size %lx\n", addr, size);
Quoted 2 lines

Where does this limitation of not loading kernel across GB boundary come from?

Quoted 9 lines

in kernel arch/x86/kernel/head_64.S

it only set first 1G ident mapping. and if it find that code is above 1G, it will set extra ident mapping
for new _text.._end.
To make checking and add extra mapping simple and also save two extra pages for mapping.
Limit that _text.._end in them same GB range.

No, this is backwards.

We should fix that limitation instead.

-hpa

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

author
#9 lore raw

Re: [PATCH v3 4/4] kexec, x86_64: Load bzImage64 above 4G

Quoted 12 lines · H. Peter Anvin
Quoted 10 lines · Yinghai Lu

in kernel arch/x86/kernel/head_64.S

it only set first 1G ident mapping. and if it find that code is above 1G, it will set extra ident mapping
for new _text.._end.
To make checking and add extra mapping simple and also save two extra pages for mapping.
Limit that _text.._end in them same GB range.

Quoted 1 line

No, this is backwards.

old one: it limited bzImage in [0,1G) aka the first 1G.

Now we can put it in any aligned 1G range.

So how could it be called backwards?

Quoted 2 lines

We should fix that limitation instead.

sure, but that will make arch/x86/boot/compressed/head_64.S not need complicated.

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#10 lore raw

Re: [PATCH v3 4/4] kexec, x86_64: Load bzImage64 above 4G

Quoted 13 lines · Yinghai Lu
Quoted 12 lines · H. Peter Anvin
Quoted 10 lines · Yinghai Lu

in kernel arch/x86/kernel/head_64.S

it only set first 1G ident mapping. and if it find that code is above 1G, it will set extra ident mapping
for new _text.._end.
To make checking and add extra mapping simple and also save two extra pages for mapping.
Limit that _text.._end in them same GB range.

Quoted 8 lines
Quoted 1 line

No, this is backwards.

old one: it limited bzImage in [0,1G) aka the first 1G.

Now we can put it in any aligned 1G range.

So how could it be called backwards?

Because you're adding a more complicated hack.

Quoted 6 lines
Quoted 2 lines

We should fix that limitation instead.

sure, but that will make arch/x86/boot/compressed/head_64.S not need complicated.

But it makes the bootloaders more complicated, and the bootloaders are harder to fix.

-hpa

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

author
#11 lore raw

Re: [PATCH v3 4/4] kexec, x86_64: Load bzImage64 above 4G

Quoted 16 lines · H. Peter Anvin
Quoted 15 lines · Yinghai Lu
Quoted 13 lines · H. Peter Anvin
Quoted 10 lines · Yinghai Lu

in kernel arch/x86/kernel/head_64.S

it only set first 1G ident mapping. and if it find that code is above 1G, it will set extra ident mapping
for new _text.._end.
To make checking and add extra mapping simple and also save two extra pages for mapping.
Limit that _text.._end in them same GB range.

No, this is backwards.

Quoted 8 lines
Quoted 6 lines

old one: it limited bzImage in [0,1G) aka the first 1G.

Now we can put it in any aligned 1G range.

So how could it be called backwards?

Because you're adding a more complicated hack.

not that complicated, and it only add 7 lines

        /* same GB ? */
        while ((addr >> 30) != ((addr + size - 1) >> 30)) {
                addr = locate_hole(info, size, align, 0x100000,
                                 round_down(addr + size - 1, (1UL<<30)), -1);
                if (addr == ULONG_MAX)
                        die("can not load bzImage64");
        }
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines

We should fix that limitation instead.

sure, but that will make arch/x86/boot/compressed/head_64.S not need complicated.

If that add cover cross GB boundary handling in head_64.S, may need another 100 line code
for checking and etc.

Also will need another two spare pages for cross 512G boundary.

Quoted 3 lines

But it makes the bootloaders more complicated, and the bootloaders are harder to fix.

current bootloader does not have this feature and will add the feature. and looks like kexec is only one at this point.

BTW, is there any 64bit boot loader?

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#12 lore raw

Re: [PATCH v3 4/4] kexec, x86_64: Load bzImage64 above 4G

Yes.

Quoted 61 lines · Yinghai Lu
Quoted 2 lines · H. Peter Anvin
Quoted 1 line · Yinghai Lu

On Wed, Nov 21, 2012 at 11:56 AM, H. Peter Anvin <[email protected]>

Quoted 5 lines · wrote:
Quoted 5 lines
Quoted 5 lines · Yinghai Lu
Quoted 4 lines

in kernel arch/x86/kernel/head_64.S

it only set first 1G ident mapping. and if it find that code is

above

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

1G, it will set extra ident mapping
for new _text.._end.
To make checking and add extra mapping simple and also save two

extra

Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
Quoted 3 lines

pages for mapping.
Limit that _text.._end in them same GB range.

No, this is backwards.

Quoted 8 lines
Quoted 6 lines

old one: it limited bzImage in [0,1G) aka the first 1G.

Now we can put it in any aligned 1G range.

So how could it be called backwards?

Because you're adding a more complicated hack.

not that complicated, and it only add 7 lines

       /* same GB ? */
       while ((addr >> 30) != ((addr + size - 1) >> 30)) {
               addr = locate_hole(info, size, align, 0x100000,
                          round_down(addr + size - 1, (1UL<<30)), -1);
               if (addr == ULONG_MAX)
                       die("can not load bzImage64");
       }
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines

We should fix that limitation instead.

sure, but that will make arch/x86/boot/compressed/head_64.S not need complicated.

If that add cover cross GB boundary handling in head_64.S, may need another 100 line code
for checking and etc.

Also will need another two spare pages for cross 512G boundary.

Quoted 2 lines

But it makes the bootloaders more complicated, and the bootloaders

are

Quoted 1 line

harder to fix.

current bootloader does not have this feature and will add the feature. and looks like kexec is only one at this point.

BTW, is there any 64bit boot loader?

Signature · 6 lines
Sent from my mobile phone. Please excuse brevity and lack of formatting.

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec
#13 lore raw

Re: [PATCH v3 4/4] kexec, x86_64: Load bzImage64 above 4G

In reply to Yinghai Lu
Quoted 10 lines · Yinghai Lu
Quoted 5 lines
Quoted 5 lines
Quoted 2 lines

We should fix that limitation instead.

sure, but that will make arch/x86/boot/compressed/head_64.S not need complicated.

If that add cover cross GB boundary handling in head_64.S, may need another 100 line code
for checking and etc.

That seems unlikely.

Quoted 1 line

Also will need another two spare pages for cross 512G boundary.

Doesn't seem like a problem.

Let me be blunt: either we do it right or we don't do it at all.

-hpa

Signature · 8 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.


_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec
author
#14 lore raw

Re: [PATCH v3 4/4] kexec, x86_64: Load bzImage64 above 4G

Quoted 7 lines · H. Peter Anvin
Quoted 2 lines

Also will need another two spare pages for cross 512G boundary.

Doesn't seem like a problem.

Let me be blunt: either we do it right or we don't do it at all.

ok, please check the version that cover gb boundary.

it is about 100 lines more than the version that does not handle crossing.

test on cross 1G, 5G, 512G, 513G.

Thanks

Yinghai

Subject: [PATCH] x86, 64bit: add support for loading kernel above 512G

Current kernel is not allowed to be loaded above 512g, it thinks that address is too big.

We only need to add one extra spare page for needed level3 to point another 512g range.

Need to check _text range and set level4 pg to point to that spare level3 page, and set level3 to point to level2 page to cover [_text, _end] with extra mapping.

We need this to put relocatable bzImage high above 512g.

-v2: handling cross GB boundary that hpa insists on.
test on cross 1G, 5G, 512g, 513g.
should double check on cross 1024g, but it should work.

Cc "Eric W. Biederman" <[email protected]>
---
 arch/x86/kernel/head_64.S |  142 ++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 131 insertions(+), 11 deletions(-)
arch/x86/kernel/head_64.S +131 -11
Index: linux-2.6/arch/x86/kernel/head_64.S
===================================================================
@@ -78,12 +78,6 @@ startup_64:
 	testl	%eax, %eax
 	jnz	bad_address
 
-	/* Is the address too large? */
-	leaq	_text(%rip), %rdx
-	movq	$PGDIR_SIZE, %rax
-	cmpq	%rax, %rdx
-	jae	bad_address
-
 	/* Fixup the physical addresses in the page table
 	 */
 	addq	%rbp, init_level4_pgt + 0(%rip)
@@ -97,28 +91,147 @@ startup_64:
 
 	addq	%rbp, level2_fixmap_pgt + (506*8)(%rip)
 
-	/* Add an Identity mapping if I am above 1G */
+	/* Add an Identity mapping if _end is above 1G */
+	leaq	_end(%rip), %r9
+	decq	%r9
+	cmp	$PUD_SIZE, %r9
+	jl	ident_complete
+
+	/* get end */
+	andq	$PMD_PAGE_MASK, %r9
+	/* round start to 1G if it is below 1G */
 	leaq	_text(%rip), %rdi
 	andq	$PMD_PAGE_MASK, %rdi
+	cmp	$PUD_SIZE, %rdi
+	jg	1f
+	movq	$PUD_SIZE, %rdi
+1:
+	/* get 512G index */
+	movq	%r9, %r10
+	shrq	$PGDIR_SHIFT, %r10
+	andq	$(PTRS_PER_PGD - 1), %r10
+	movq	%rdi, %rax
+	shrq	$PGDIR_SHIFT, %rax
+	andq	$(PTRS_PER_PGD - 1), %rax
+
+	/* cross two 512G ? */
+	cmp	%r10, %rax
+	jne	set_level3_other_512g
+
+	/* all in first 512G ? */
+	cmp	$0, %rax
+	je	skip_level3_spare
+
+	/* same 512G other than first 512g */
+	leaq    (level3_spare_pgt - __START_KERNEL_map + _KERNPG_TABLE)(%rbp), %rdx
+	leaq    init_level4_pgt(%rip), %rbx
+	movq    %rdx, 0(%rbx, %rax, 8)
+	addq    $L4_PAGE_OFFSET, %rax
+	movq    %rdx, 0(%rbx, %rax, 8)
+
+	/* get 1G index */
+	movq    %r9, %r10
+	shrq    $PUD_SHIFT, %r10
+	andq    $(PTRS_PER_PUD - 1), %r10
+        movq    %rdi, %rax
+        shrq    $PUD_SHIFT, %rax
+        andq    $(PTRS_PER_PUD - 1), %rax
+
+	/* same 1G ? */
+	cmp     %r10, %rax
+	je	set_level2_start_only_not_first_512g
+
+	/* set level2 for end */
+	leaq    level3_spare_pgt(%rip), %rbx
+	leaq    (level2_spare2_pgt - __START_KERNEL_map + _KERNPG_TABLE)(%rbp), %rdx
+	movq    %rdx, 0(%rbx, %r10, 8)
+
+set_level2_start_only_not_first_512g:
+	leaq    level3_spare_pgt(%rip), %rbx
+	leaq    (level2_spare_pgt - __START_KERNEL_map + _KERNPG_TABLE)(%rbp), %rdx
+	movq    %rdx, 0(%rbx, %rax, 8)
+
+	jmp	set_level2_spare
+
+set_level3_other_512g:
+	/* start is in first 512G ? */
+	cmp	$0, %rax
+	/* for level2 last on first 512g */
+	leaq	level3_ident_pgt(%rip), %rcx
+	je	set_level2_start_other_512g
+
+	/* Set level3 for _text */
+	leaq	(level3_spare_pgt - __START_KERNEL_map + _KERNPG_TABLE)(%rbp), %rdx
+	leaq	init_level4_pgt(%rip), %rbx
+	movq	%rdx, 0(%rbx, %rax, 8)
+	addq	$L4_PAGE_OFFSET, %rax
+	movq	%rdx, 0(%rbx, %rax, 8)
 
+	/* for level2 last not on first 512G */
+	leaq	level3_spare_pgt(%rip), %rcx
+
+set_level2_start_other_512g:
+	/* always need to set level2 */
 	movq	%rdi, %rax
 	shrq	$PUD_SHIFT, %rax
 	andq	$(PTRS_PER_PUD - 1), %rax
-	jz	ident_complete
-
+	movq	%rcx, %rbx    /* %rcx has level3_spare_pgt or level3_ident_pgt */
 	leaq	(level2_spare_pgt - __START_KERNEL_map + _KERNPG_TABLE)(%rbp), %rdx
+	movq	%rdx, 0(%rbx, %rax, 8)
+
+set_level3_end_other_512g:
+	leaq	(level3_spare2_pgt - __START_KERNEL_map + _KERNPG_TABLE)(%rbp), %rdx
+	leaq	init_level4_pgt(%rip), %rbx
+	movq	%rdx, 0(%rbx, %r10, 8)
+	addq	$L4_PAGE_OFFSET, %r10
+	movq	%rdx, 0(%rbx, %r10, 8)
+
+	/* always need to set level2 */
+	movq	%r9, %r10
+	shrq	$PUD_SHIFT, %r10
+	andq	$(PTRS_PER_PUD - 1), %r10
+	leaq	level3_spare2_pgt(%rip), %rbx
+	leaq	(level2_spare2_pgt - __START_KERNEL_map + _KERNPG_TABLE)(%rbp), %rdx
+	movq	%rdx, 0(%rbx, %r10, 8)
+
+	jmp	set_level2_spare
+
+skip_level3_spare:
+	/* get 1G index */
+	movq	%r9, %r10
+	shrq	$PUD_SHIFT, %r10
+	andq	$(PTRS_PER_PUD - 1), %r10
+	movq	%rdi, %rax
+	shrq	$PUD_SHIFT, %rax
+	andq	$(PTRS_PER_PUD - 1), %rax
+
+	/* same 1G ? */
+	cmp	%r10, %rax
+	je	set_level2_start_only_first_512g
+
+	/* set level2 without level3 spare */
 	leaq	level3_ident_pgt(%rip), %rbx
+	leaq	(level2_spare2_pgt - __START_KERNEL_map + _KERNPG_TABLE)(%rbp), %rdx
+	movq	%rdx, 0(%rbx, %r10, 8)
+
+set_level2_start_only_first_512g:
+	/*  set level2 without level3 spare */
+	leaq	level3_ident_pgt(%rip), %rbx
+	leaq	(level2_spare_pgt - __START_KERNEL_map + _KERNPG_TABLE)(%rbp), %rdx
 	movq	%rdx, 0(%rbx, %rax, 8)
 
+set_level2_spare:
 	movq	%rdi, %rax
 	shrq	$PMD_SHIFT, %rax
 	andq	$(PTRS_PER_PMD - 1), %rax
 	leaq	__PAGE_KERNEL_IDENT_LARGE_EXEC(%rdi), %rdx
 	leaq	level2_spare_pgt(%rip), %rbx
-	leaq	_end(%rip), %r8
-	decq	%r8
+	movq	%r9, %r8
 	shrq	$PMD_SHIFT, %r8
 	andq	$(PTRS_PER_PMD - 1), %r8
+	cmp	%r8, %rax
+	jl	1f
+	addq	$PTRS_PER_PMD, %r8
 1:	movq	%rdx, 0(%rbx, %rax, 8)
 	addq	$PMD_SIZE, %rdx
 	incq	%rax
@@ -435,8 +548,15 @@ NEXT_PAGE(level2_kernel_pgt)
 	PMDS(0, __PAGE_KERNEL_LARGE_EXEC,
 		KERNEL_IMAGE_SIZE/PMD_SIZE)
 
+NEXT_PAGE(level3_spare_pgt)
+	.fill   512, 8, 0
+NEXT_PAGE(level3_spare2_pgt)
+	.fill   512, 8, 0
+
 NEXT_PAGE(level2_spare_pgt)
 	.fill   512, 8, 0
+NEXT_PAGE(level2_spare2_pgt)
+	.fill   512, 8, 0
 
 #undef PMDS
 #undef NEXT_PAGE

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#15 lore raw

Re: [PATCH v3 4/4] kexec, x86_64: Load bzImage64 above 4G

In reply to Yinghai Lu

On Tue, Nov 20, 2012 at 11:31:38PM -0800, Yinghai Lu wrote:

[..]

Quoted 34 lines
kexec/arch/x86_64/kexec-bzImage64.c new file +34 -0
+int bzImage64_probe(const char *buf, off_t len)
+{
+	const struct x86_linux_header *header;
+	if ((uintmax_t)len < (uintmax_t)(2 * 512)) {
+		if (probe_debug) {
+			fprintf(stderr, "File is too short to be a bzImage!\n");
+		}
+		return -1;
+	}
+	header = (const struct x86_linux_header *)buf;
+	if (memcmp(header->header_magic, "HdrS", 4) != 0) {
+		if (probe_debug) {
+			fprintf(stderr, "Not a bzImage\n");
+		}
+		return -1;
+	}
+	if (header->boot_sector_magic != 0xAA55) {
+		if (probe_debug) {
+			fprintf(stderr, "No x86 boot sector present\n");
+		}
+		/* No x86 boot sector present */
+		return -1;
+	}
+	if (header->protocol_version < 0x020C) {
+		if (probe_debug) {
+			fprintf(stderr, "Must be at least protocol version 2.12\n");
+		}
+		/* Must be at least protocol version 2.12 */
+		return -1;
+	}
+	if ((header->loadflags & 1) == 0) {
+		if (probe_debug) {
+			fprintf(stderr, "zImage not a bzImage\n");
+		}

kexec/arch/x86_64/kexec-bzImage64.c line 89

Quoted 10 lines
kexec/arch/x86_64/kexec-bzImage64.c new file +10 -0
+		/* Not a bzImage */
+		return -1;
+	}
+	if (!(header->xloadflags & 1)) {
+		if (probe_debug) {
+			fprintf(stderr, "Not a bzImage64\n");
+		}
+		/* Must be LOADED_ABOVE_4G */
+		return -1;
+	}

So how do I force a 16bit or 32bit entry using a bzImage64?

Thanks
Vivek

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

author
#16 lore raw

Re: [PATCH v3 4/4] kexec, x86_64: Load bzImage64 above 4G

Quoted 41 lines · Vivek Goyal

On Tue, Nov 20, 2012 at 11:31:38PM -0800, Yinghai Lu wrote:

[..]

Quoted 38 lines
kexec/arch/x86_64/kexec-bzImage64.c new file +38 -0
+int bzImage64_probe(const char *buf, off_t len)
+{
+     const struct x86_linux_header *header;
+     if ((uintmax_t)len < (uintmax_t)(2 * 512)) {
+             if (probe_debug) {
+                     fprintf(stderr, "File is too short to be a bzImage!\n");
+             }
+             return -1;
+     }
+     header = (const struct x86_linux_header *)buf;
+     if (memcmp(header->header_magic, "HdrS", 4) != 0) {
+             if (probe_debug) {
+                     fprintf(stderr, "Not a bzImage\n");
+             }
+             return -1;
+     }
+     if (header->boot_sector_magic != 0xAA55) {
+             if (probe_debug) {
+                     fprintf(stderr, "No x86 boot sector present\n");
+             }
+             /* No x86 boot sector present */
+             return -1;
+     }
+     if (header->protocol_version < 0x020C) {
+             if (probe_debug) {
+                     fprintf(stderr, "Must be at least protocol version 2.12\n");
+             }
+             /* Must be at least protocol version 2.12 */
+             return -1;
+     }
+     if ((header->loadflags & 1) == 0) {
+             if (probe_debug) {
+                     fprintf(stderr, "zImage not a bzImage\n");
+             }
+             /* Not a bzImage */
+             return -1;
+     }
+     if (!(header->xloadflags & 1)) {
Quoted 8 lines

kexec/arch/x86_64/kexec-bzImage64.c line 89

Quoted 6 lines
kexec/arch/x86_64/kexec-bzImage64.c new file +6 -0
+             if (probe_debug) {
+                     fprintf(stderr, "Not a bzImage64\n");
+             }
+             /* Must be LOADED_ABOVE_4G */
+             return -1;
+     }

So how do I force a 16bit or 32bit entry using a bzImage64?

kexec -t bzImage -l ....
will load low and use 32bit entry.

kexec -t bzImage64 -l ...
kexec -l ...
will try to load high and use 64bit entry.

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#17 lore raw

Re: [PATCH v3 4/4] kexec, x86_64: Load bzImage64 above 4G

Quoted 10 lines · Yinghai Lu
Quoted 2 lines

So how do I force a 16bit or 32bit entry using a bzImage64?

kexec -t bzImage -l ....
will load low and use 32bit entry.

kexec -t bzImage64 -l ...
kexec -l ...
will try to load high and use 64bit entry.

I don't see any difference...

-hpa

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

author
#18 lore raw

Re: [PATCH v3 4/4] kexec, x86_64: Load bzImage64 above 4G

Quoted 7 lines · H. Peter Anvin
Quoted 6 lines · Yinghai Lu
Quoted 2 lines

So how do I force a 16bit or 32bit entry using a bzImage64?

kexec -t bzImage -l ....
will load low and use 32bit entry.

Quoted 8 lines
Quoted 4 lines

kexec -t bzImage64 -l ...
kexec -l ...
will try to load high and use 64bit entry.

I don't see any difference...

kexec/arch/x86_64/kexec-x86_64.c +1 -0
@@ -37,6 +37,7 @@ struct file_type file_type[] = {
        { "multiboot-x86", multiboot_x86_probe, multiboot_x86_load,
          multiboot_x86_usage },
        { "elf-x86", elf_x86_probe, elf_x86_load, elf_x86_usage },
+       { "bzImage64", bzImage64_probe, bzImage64_load, bzImage64_usage },
        { "bzImage", bzImage_probe, bzImage_load, bzImage_usage },
        { "beoboot-x86", beoboot_probe, beoboot_load, beoboot_usage },
        { "nbi-x86", nbi_probe, nbi_load, nbi_usage },

bzImage64_probe will be run before bzImage_probe.

and if it find that is 64bit, bzImage_probe will not be executed.

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#19 lore raw

Re: [PATCH v3 4/4] kexec, x86_64: Load bzImage64 above 4G

In reply to Yinghai Lu

On Wed, Nov 21, 2012 at 11:50:56AM -0800, Yinghai Lu wrote:

[..]

Quoted 5 lines
Quoted 1 line

So how do I force a 16bit or 32bit entry using a bzImage64?

kexec -t bzImage -l ....
will load low and use 32bit entry.

Ok, so user needs to enforce image type (using -t option) to bzImage (for a bzImage which supports 64bit entry point) to be able to use 32bit entry.

I think a better option is that bzImage64 loader parses the user specified entry options and call into 32bit bzImage loader if user is asking for 32bit or 16bit entry. For 16bit, we already have option --real-mode option. May be we need to introduce another one for forcing 32bit entry, say --entry-32bit or --protected-mode (whatever makes sense).

Eric will know better but I do think that bzImage64 loader should be able to parse user specified entry point and honor that.

Quoted 3 lines

kexec -t bzImage64 -l ...
kexec -l ...
will try to load high and use 64bit entry.

This one violates the existing syntax where --real-mode is supposed to jump to real mode entry point of bzImage.

Eric will know better but I do think that bzImage64 loader should be able to parse user specified entry point and honor that.

Thanks
Vivek

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

author
#20 lore raw

Re: [PATCH v3 4/4] kexec, x86_64: Load bzImage64 above 4G

Quoted 13 lines · Vivek Goyal

On Wed, Nov 21, 2012 at 11:50:56AM -0800, Yinghai Lu wrote:

[..]

Quoted 5 lines
Quoted 1 line

So how do I force a 16bit or 32bit entry using a bzImage64?

kexec -t bzImage -l ....
will load low and use 32bit entry.

Ok, so user needs to enforce image type (using -t option) to bzImage (for a bzImage which supports 64bit entry point) to be able to use 32bit entry.

Quoted 5 lines

I think a better option is that bzImage64 loader parses the user specified entry options and call into 32bit bzImage loader if user is asking for 32bit or 16bit entry. For 16bit, we already have option --real-mode option. May be we need to introduce another one for forcing 32bit entry, say --entry-32bit or --protected-mode (whatever makes sense).

that is doable.

add checking entry-32bit and real-mode checking in kexec-bzImage64.c and bail early to leave kexec-bzImage.c to take over.

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#21 lore raw

Re: [PATCH v3 4/4] kexec, x86_64: Load bzImage64 above 4G

Quoted 20 lines · Yinghai Lu
Quoted 13 lines · Vivek Goyal

On Wed, Nov 21, 2012 at 11:50:56AM -0800, Yinghai Lu wrote:

[..]

Quoted 5 lines
Quoted 1 line

So how do I force a 16bit or 32bit entry using a bzImage64?

kexec -t bzImage -l ....
will load low and use 32bit entry.

Ok, so user needs to enforce image type (using -t option) to bzImage (for a bzImage which supports 64bit entry point) to be able to use 32bit entry.

Quoted 5 lines

I think a better option is that bzImage64 loader parses the user specified entry options and call into 32bit bzImage loader if user is asking for 32bit or 16bit entry. For 16bit, we already have option --real-mode option. May be we need to introduce another one for forcing 32bit entry, say --entry-32bit or --protected-mode (whatever makes sense).

Quoted 4 lines

that is doable.

add checking entry-32bit and real-mode checking in kexec-bzImage64.c and bail early to leave kexec-bzImage.c to take over.

Or actually can we do reverse. Do not introduce new image format bzImage64. In existing bzImage loader if bzImage version is greater than 0x020c (or whatever version has 64bit entry extension), just call into load_bzImage64().

Thanks
Vivek

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

author
#22 lore raw

Re: [PATCH v3 4/4] kexec, x86_64: Load bzImage64 above 4G

Quoted 5 lines · Vivek Goyal

Or actually can we do reverse. Do not introduce new image format bzImage64. In existing bzImage loader if bzImage version is greater than 0x020c (or whatever version has 64bit entry extension), just call into load_bzImage64().

Eric wanted me to separate that out.
and you want me to put them back?

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#23 lore raw

Re: [PATCH v3 4/4] kexec, x86_64: Load bzImage64 above 4G

In reply to Yinghai Lu
Quoted 51 lines · Yinghai Lu
Quoted 41 lines · Vivek Goyal

On Tue, Nov 20, 2012 at 11:31:38PM -0800, Yinghai Lu wrote:

[..]

Quoted 38 lines
kexec/arch/x86_64/kexec-bzImage64.c new file +38 -0
+int bzImage64_probe(const char *buf, off_t len)
+{
+     const struct x86_linux_header *header;
+     if ((uintmax_t)len < (uintmax_t)(2 * 512)) {
+             if (probe_debug) {
+                     fprintf(stderr, "File is too short to be a bzImage!\n");
+             }
+             return -1;
+     }
+     header = (const struct x86_linux_header *)buf;
+     if (memcmp(header->header_magic, "HdrS", 4) != 0) {
+             if (probe_debug) {
+                     fprintf(stderr, "Not a bzImage\n");
+             }
+             return -1;
+     }
+     if (header->boot_sector_magic != 0xAA55) {
+             if (probe_debug) {
+                     fprintf(stderr, "No x86 boot sector present\n");
+             }
+             /* No x86 boot sector present */
+             return -1;
+     }
+     if (header->protocol_version < 0x020C) {
+             if (probe_debug) {
+                     fprintf(stderr, "Must be at least protocol version 2.12\n");
+             }
+             /* Must be at least protocol version 2.12 */
+             return -1;
+     }
+     if ((header->loadflags & 1) == 0) {
+             if (probe_debug) {
+                     fprintf(stderr, "zImage not a bzImage\n");
+             }
+             /* Not a bzImage */
+             return -1;
+     }
+     if (!(header->xloadflags & 1)) {
Quoted 8 lines

kexec/arch/x86_64/kexec-bzImage64.c line 89

Quoted 6 lines
kexec/arch/x86_64/kexec-bzImage64.c new file +6 -0
+             if (probe_debug) {
+                     fprintf(stderr, "Not a bzImage64\n");
+             }
+             /* Must be LOADED_ABOVE_4G */
+             return -1;
+     }

So how do I force a 16bit or 32bit entry using a bzImage64?

Quoted 6 lines

kexec -t bzImage -l ....
will load low and use 32bit entry.

kexec -t bzImage64 -l ...
kexec -l ...
will try to load high and use 64bit entry.

Also bzImage64 is not really a new image format. It is just enhancement of bzImage format. We keep on doing extention of bzImage and don't call it a new image format. I am not sure how good an idea it is to export the notion of new image type bzImage64 to user.

Thanks
Vivek

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#24 lore raw

Re: [PATCH v3 4/4] kexec, x86_64: Load bzImage64 above 4G

Quoted 8 lines · Vivek Goyal
Quoted 7 lines · Yinghai Lu
Quoted 2 lines · Vivek Goyal

So how do I force a 16bit or 32bit entry using a bzImage64?

kexec -t bzImage -l ....
will load low and use 32bit entry.

Quoted 8 lines
Quoted 3 lines

kexec -t bzImage64 -l ...
kexec -l ...
will try to load high and use 64bit entry.

Also bzImage64 is not really a new image format. It is just enhancement of bzImage format. We keep on doing extention of bzImage and don't call it a new image format. I am not sure how good an idea it is to export the notion of new image type bzImage64 to user.

For what the loader has to do bzImage64 is effectively a new format, and one way or another needs to be handled by separate functions so that the code remains readable.

I asked YH to add the code that way because it means only a 64bit kexec has to carry that code and we don't have 64bit dependencies in in the 32bit build that will break. The code to prepare boot_params is still shared.

Chaining to the 32bit loader if someone asks for --real-mode or perhaps --entry32 seems quite reasonable and only a couple of lines of code so I have not objections to that.

While development is on-going forcing the image type seems very reasonable, but when the smoke clears I would like to see the bzImage64 format chaining to bzImage for the cases it does not handle.

But with respect to autodetection only having bzImage64 kick in when loading a 64bit kernel is possible looks like the right way to go.

Eric

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec