Skip to contentSkip to conversation

Unable to boot very old Linux kernels

PATCH In review Piotr Krysiuk 2 participants 5 messages Mar 17, 2014 – Mar 24, 2014

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Unable to boot very old Linux kernels

Hi,

I occasionally need to boot a very old Linux kernel.

This works fine with old versions of GRUB, from before relocator was introduced. However the kernel cannot be started by recent versions of GRUB - machine simply restarts as soon as GRUB passes control to Linux. As mentioned above this affects very old Linux only, so very few users (if any) would care. But as I have a patch, here it is.

I tracked the issues to code initializing BSS that is used by old Linux kernels. See code following "Clear BSS" on
https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/arch/x86_64/boot/compressed/head.S?h=linux-2.6.17.y#n57

AFAIK old Linux kernels do not provide information allowing boot loader to determine end of BSS. As the consequence, current GRUB may place GPT in the area overlapping with BSS sections of old Linux kernels. The location of GPT was changed at the same time when relocator was added, introducing regression.

In order to improve compatibility with these old kernels, we could switch back to old strategy and simply place GPT close to end of physical memory.

Best regards,

Piotr Krysiuk

---
 ChangeLog                      |    5 +++++
 grub-core/lib/i386/relocator.c |    2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)
ChangeLog +5 -0
index 770269c..5a91e5e 100644
@@ -1,3 +1,8 @@
+2014-03-17  Piotr Krysiuk  <[email protected]>
+
+	* grub-core/lib/i386/relocator.c: Moved GDT to end of physical memory
+	to avoid collision with old Linux BSS.
+
 2014-02-28  Vladimir Serbinenko  <[email protected]>
 
 	* include/grub/i386/openbsd_bootarg.h: Add addr and frequency fields.
grub-core/lib/i386/relocator.c +1 -1
index d2a1b27..523f669 100644
@@ -84,7 +84,7 @@ grub_relocator32_boot (struct grub_relocator *rel,
   err = grub_relocator_alloc_chunk_align (rel, &ch, 0,
 					  (0xffffffff - RELOCATOR_SIZEOF (32))
 					  + 1, RELOCATOR_SIZEOF (32), 16,
-					  GRUB_RELOCATOR_PREFERENCE_NONE,
+					  GRUB_RELOCATOR_PREFERENCE_HIGH,
 					  avoid_efi_bootservices);
   if (err)
     return err;
Signature · 1 line
1.7.9.5
#1 lore raw
Quoted 14 lines · Piotr Krysiuk

Hi,

I occasionally need to boot a very old Linux kernel.

This works fine with old versions of GRUB, from before relocator was introduced. However the kernel cannot be started by recent versions of GRUB - machine simply restarts as soon as GRUB passes control to Linux. As mentioned above this affects very old Linux only, so very few users (if any) would care. But as I have a patch, here it is.

I tracked the issues to code initializing BSS that is used by old Linux kernels. See code following "Clear BSS" on
https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/arch/x86_64/boot/compressed/head.S?h=linux-2.6.17.y#n57

Quoted 6 lines

AFAIK old Linux kernels do not provide information allowing boot loader to determine end of BSS. As the consequence, current GRUB may place GPT in the area overlapping with BSS sections of old Linux kernels. The location of GPT was changed at the same time when relocator was added, introducing regression.

Top of memory doesn't sound like a right place. Could you try with

Quoted 2 lines

err = grub_relocator_alloc_chunk_align (rel, &ch, 0,
(0xa0000 - RELOCATOR_SIZEOF (32)), ...

This will put GDT in low memory

Quoted 39 lines

In order to improve compatibility with these old kernels, we could switch back to old strategy and simply place GPT close to end of physical memory.

Best regards,

Piotr Krysiuk

---
 ChangeLog                      |    5 +++++
 grub-core/lib/i386/relocator.c |    2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)
ChangeLog +5 -0
index 770269c..5a91e5e 100644
@@ -1,3 +1,8 @@
+2014-03-17  Piotr Krysiuk  <[email protected]>
+
+	* grub-core/lib/i386/relocator.c: Moved GDT to end of physical memory
+	to avoid collision with old Linux BSS.
+
 2014-02-28  Vladimir Serbinenko  <[email protected]>
 
 	* include/grub/i386/openbsd_bootarg.h: Add addr and frequency fields.
grub-core/lib/i386/relocator.c +1 -1
index d2a1b27..523f669 100644
@@ -84,7 +84,7 @@ grub_relocator32_boot (struct grub_relocator *rel,
   err = grub_relocator_alloc_chunk_align (rel, &ch, 0,
 					  (0xffffffff - RELOCATOR_SIZEOF (32))
 					  + 1, RELOCATOR_SIZEOF (32), 16,
-					  GRUB_RELOCATOR_PREFERENCE_NONE,
+					  GRUB_RELOCATOR_PREFERENCE_HIGH,
 					  avoid_efi_bootservices);
   if (err)
     return err;
author
#2 lore raw

Hi,

Tested suggested parameters under Qemu, so calling grub_relocator_alloc_chunk_align with following:
max_addr = (0xa0000 - RELOCATOR_SIZEOF (32)) + 1 preference = GRUB_RELOCATOR_PREFERENCE_LOW

This fails to allocate from low memory and falls back to top of physical memory, ignoring preference. Relevant part of debug log for relocator (full log included as attachment):
lib/relocator.c:434: trying to allocate in 0x1000-0x9ff31 aligned
0x10 size 0xd0
lib/relocator.c:1411: Adjusted limits from 1000-9ff31 to 0-100000 lib/relocator.c:434: trying to allocate in 0x0-0x100000 aligned 0x10 size 0xd0 lib/relocator.c:434: trying to allocate in 0x2a9000-0xffffffff
aligned 0x1 size 0xd0
lib/relocator.c:1186: allocated: 0x3fff7c20+0xd0

See malloc_in_range calls in grub_relocator_alloc_chunk_align to see why preference is ignored after first failure. Looking at malloc_in_range, I don't see any events to explain why allocation in range 0x1000..0x9ff31 fails. I can try to debug this later this week.

Regards,

Piotr

My code for reference:

grub-core/lib/i386/relocator.c +2 -2
index d2a1b27..e9ab529 100644
@@ -82,9 +82,9 @@ grub_relocator32_boot (struct grub_relocator *rel,
   grub_relocator_chunk_t ch;
 
   err = grub_relocator_alloc_chunk_align (rel, &ch, 0,
-                                         (0xffffffff - RELOCATOR_SIZEOF (32))
+                                         (0xa0000 - RELOCATOR_SIZEOF (32))
                                          + 1, RELOCATOR_SIZEOF (32), 16,
-                                         GRUB_RELOCATOR_PREFERENCE_NONE,
+                                         GRUB_RELOCATOR_PREFERENCE_LOW,
                                          avoid_efi_bootservices);
   if (err)
     return err;
Quoted 65 lines · Vladimir 'φ-coder/phcoder' Serbinenko
Quoted 14 lines · Piotr Krysiuk

Hi,

I occasionally need to boot a very old Linux kernel.

This works fine with old versions of GRUB, from before relocator was introduced. However the kernel cannot be started by recent versions of GRUB - machine simply restarts as soon as GRUB passes control to Linux. As mentioned above this affects very old Linux only, so very few users (if any) would care. But as I have a patch, here it is.

I tracked the issues to code initializing BSS that is used by old Linux kernels. See code following "Clear BSS" on
https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/arch/x86_64/boot/compressed/head.S?h=linux-2.6.17.y#n57

Quoted 6 lines

AFAIK old Linux kernels do not provide information allowing boot loader to determine end of BSS. As the consequence, current GRUB may place GPT in the area overlapping with BSS sections of old Linux kernels. The location of GPT was changed at the same time when relocator was added, introducing regression.

Top of memory doesn't sound like a right place. Could you try with

Quoted 2 lines

err = grub_relocator_alloc_chunk_align (rel, &ch, 0,

                                        (0xa0000 - RELOCATOR_SIZEOF (32)), ...

This will put GDT in low memory

Quoted 38 lines

In order to improve compatibility with these old kernels, we could switch back to old strategy and simply place GPT close to end of physical memory.

Best regards,

Piotr Krysiuk

---
 ChangeLog                      |    5 +++++
 grub-core/lib/i386/relocator.c |    2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)
ChangeLog +5 -0
index 770269c..5a91e5e 100644
@@ -1,3 +1,8 @@
+2014-03-17  Piotr Krysiuk  <[email protected]>
+
+     * grub-core/lib/i386/relocator.c: Moved GDT to end of physical memory
+     to avoid collision with old Linux BSS.
+
 2014-02-28  Vladimir Serbinenko  <[email protected]>
 
      * include/grub/i386/openbsd_bootarg.h: Add addr and frequency fields.
grub-core/lib/i386/relocator.c +1 -1
index d2a1b27..523f669 100644
@@ -84,7 +84,7 @@ grub_relocator32_boot (struct grub_relocator *rel,
   err = grub_relocator_alloc_chunk_align (rel, &ch, 0,
                                        (0xffffffff - RELOCATOR_SIZEOF (32))
                                        + 1, RELOCATOR_SIZEOF (32), 16,
-                                       GRUB_RELOCATOR_PREFERENCE_NONE,
+                                       GRUB_RELOCATOR_PREFERENCE_HIGH,
                                        avoid_efi_bootservices);
   if (err)
     return err;
Quoted 9 lines
Quoted 1 line

_______________________________________________
Grub-devel mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/grub-devel

script/lexer.c:321: token 259 text [
]
script/lexer.c:321: token 0 text []
script/lexer.c:321: token 288 text [linux]
script/lexer.c:321: token 289 text [(hd0)/vmlinuz]
script/lexer.c:321: token 259 text [
]
script/lexer.c:321: token 0 text []
lib/relocator.c:115: relocators_size=7
lib/relocator.c:1239: min_addr = 0x0, max_addr = 0xffffffff, target = 0x100000 lib/relocator.c:434: trying to allocate in 0x100000-0xffffffff aligned 0x1 size 0x1a9000 lib/relocator.c:1186: allocated: 0x100000+0x1a9000
lib/relocator.c:1275: allocated 0x100000/0x100000
lib/relocator.c:1293: relocators_size=7
lib/relocator.c:1301: relocators_size=7
lib/relocator.c:1308: cur = 0x3ff725c0, next = 0x0
loader/i386/linux.c:254: prot_mode_mem = 0x100000, prot_mode_target = 100000, prot_size = 1a9000 loader/i386/linux.c:878: bzImage, setup=0x1c00, size=0x1a8615
script/lexer.c:321: token 288 text [initrd]
script/lexer.c:321: token 289 text [(hd0)/initrd.gz]
script/lexer.c:321: token 259 text [
]
script/lexer.c:321: token 0 text []
lib/relocator.c:1385: chunks = 0x3ff725c0
lib/relocator.c:434: trying to allocate in 0x5fb000-0x37b75000 aligned 0x1000 size 0x47a430 lib/relocator.c:1186: allocated: 0x376fa000+0x47a430
lib/relocator.c:1397: allocated 0x376fa000/0x376fa000
lib/relocator.c:1398: chunks = 0x3ff725c0
loader/i386/linux.c:1124: Initrd, addr=0x37b75000, size=0x47a430
script/lexer.c:321: token 288 text [boot]
script/lexer.c:321: token 259 text [
]
script/lexer.c:321: token 0 text []
loader/i386/linux.c:570: real_size = 4000, mmap_size = 2000
loader/i386/linux.c:424: addr = 10000, size = 80000, need_size = 4000
loader/i386/linux.c:582: real_mode_target = 8c000, real_size = 4000, efi_mmap_size = 0 lib/relocator.c:1239: min_addr = 0x0, max_addr = 0x100000, target = 0x8c000 lib/relocator.c:434: trying to allocate in 0x2a9000-0xffffffff aligned 0x1 size 0x4000 lib/relocator.c:1186: allocated: 0x3f8559c0+0x4000
lib/relocator.c:1275: allocated 0x3f8559c0/0x8c000
lib/relocator.c:1293: relocators_size=7
lib/relocator.c:1301: relocators_size=29
lib/relocator.c:1308: cur = 0x3ff72af0, next = 0x3ff72700
loader/i386/linux.c:599: real_mode_mem = 0x3f8559c0
loader/i386/linux.c:609: code32_start = 100000
lib/relocator.c:1385: chunks = 0x3ff72af0
lib/relocator.c:434: trying to allocate in 0x1000-0x9ff31 aligned 0x10 size 0xd0 lib/relocator.c:1411: Adjusted limits from 1000-9ff31 to 0-100000
lib/relocator.c:434: trying to allocate in 0x0-0x100000 aligned 0x10 size 0xd0 lib/relocator.c:434: trying to allocate in 0x2a9000-0xffffffff aligned 0x1 size 0xd0 lib/relocator.c:1186: allocated: 0x3fff7c20+0xd0
lib/relocator.c:1466: relocators_size=29
lib/relocator.c:1474: relocators_size=51
lib/relocator.c:1480: cur = 0x3ff64750, next = 0x3ff72af0
grub_relocator32_boot: grub_relocator_alloc_chunk_align(..., GRUB_RELOCATOR_PREFERENCE_LOW,...) returned 3fff7c20 lib/relocator.c:1521: Preparing relocs (size=51)
lib/relocator.c:434: trying to allocate in 0x0-0xffffffcd aligned 0x1 size 0x33 lib/relocator.c:1186: allocated: 0x2a9000+0x33
lib/relocator.c:1533: Relocs allocated at 0x2a9000
lib/relocator.c:1548: chunk 0x3fff7c20->0x0, 0xd0
lib/relocator.c:1548: chunk 0x3f8559c0->0x8c000, 0x4000
lib/relocator.c:1548: chunk 0x376fa000->0x376fa000, 0x47a430
lib/relocator.c:1548: chunk 0x100000->0x100000, 0x1a9000
lib/relocator.c:1592: sorted chunk 0x100000->0x100000, 0x1a9000
lib/relocator.c:1592: sorted chunk 0x376fa000->0x376fa000, 0x47a430
lib/relocator.c:1592: sorted chunk 0x3f8559c0->0x8c000, 0x4000
lib/relocator.c:1592: sorted chunk 0x3fff7c20->0x0, 0xd0

author
#3 lore raw

PATCH 1/1 Unable to boot very old Linux kernels

Scratch that.

With GRUB_RELOCATOR_PREFERENCE_HIGH, Global Descriptor Table is located just before 0xa0000 like we want. I'll test it on live machine before sending updated patch.

Sorry for confusion,

Piotr

---------- Forwarded message ----------
From: Piotras <[email protected]>
Date: Sun, Mar 23, 2014 at 10:50 PM
Subject: Re: [PATCH] Unable to boot very old Linux kernels
To: The development of GNU GRUB <[email protected]>

Hi,

Tested suggested parameters under Qemu, so calling grub_relocator_alloc_chunk_align with following:
max_addr = (0xa0000 - RELOCATOR_SIZEOF (32)) + 1 preference = GRUB_RELOCATOR_PREFERENCE_LOW

This fails to allocate from low memory and falls back to top of physical memory, ignoring preference. Relevant part of debug log for relocator (full log included as attachment):
lib/relocator.c:434: trying to allocate in 0x1000-0x9ff31 aligned
0x10 size 0xd0
lib/relocator.c:1411: Adjusted limits from 1000-9ff31 to 0-100000 lib/relocator.c:434: trying to allocate in 0x0-0x100000 aligned 0x10 size 0xd0 lib/relocator.c:434: trying to allocate in 0x2a9000-0xffffffff
aligned 0x1 size 0xd0
lib/relocator.c:1186: allocated: 0x3fff7c20+0xd0

See malloc_in_range calls in grub_relocator_alloc_chunk_align to see why preference is ignored after first failure. Looking at malloc_in_range, I don't see any events to explain why allocation in range 0x1000..0x9ff31 fails. I can try to debug this later this week.

Regards,

Piotr

My code for reference:

grub-core/lib/i386/relocator.c +2 -2
index d2a1b27..e9ab529 100644
@@ -82,9 +82,9 @@ grub_relocator32_boot (struct grub_relocator *rel,
   grub_relocator_chunk_t ch;
 
   err = grub_relocator_alloc_chunk_align (rel, &ch, 0,
-                                         (0xffffffff - RELOCATOR_SIZEOF (32))
+                                         (0xa0000 - RELOCATOR_SIZEOF (32))
                                          + 1, RELOCATOR_SIZEOF (32), 16,
-                                         GRUB_RELOCATOR_PREFERENCE_NONE,
+                                         GRUB_RELOCATOR_PREFERENCE_LOW,
                                          avoid_efi_bootservices);
   if (err)
     return err;
Quoted 65 lines · Vladimir 'φ-coder/phcoder' Serbinenko
Quoted 14 lines · Piotr Krysiuk

Hi,

I occasionally need to boot a very old Linux kernel.

This works fine with old versions of GRUB, from before relocator was introduced. However the kernel cannot be started by recent versions of GRUB - machine simply restarts as soon as GRUB passes control to Linux. As mentioned above this affects very old Linux only, so very few users (if any) would care. But as I have a patch, here it is.

I tracked the issues to code initializing BSS that is used by old Linux kernels. See code following "Clear BSS" on
https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/arch/x86_64/boot/compressed/head.S?h=linux-2.6.17.y#n57

Quoted 6 lines

AFAIK old Linux kernels do not provide information allowing boot loader to determine end of BSS. As the consequence, current GRUB may place GPT in the area overlapping with BSS sections of old Linux kernels. The location of GPT was changed at the same time when relocator was added, introducing regression.

Top of memory doesn't sound like a right place. Could you try with

Quoted 2 lines

err = grub_relocator_alloc_chunk_align (rel, &ch, 0,

                                        (0xa0000 - RELOCATOR_SIZEOF (32)), ...

This will put GDT in low memory

Quoted 38 lines

In order to improve compatibility with these old kernels, we could switch back to old strategy and simply place GPT close to end of physical memory.

Best regards,

Piotr Krysiuk

---
 ChangeLog                      |    5 +++++
 grub-core/lib/i386/relocator.c |    2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)
ChangeLog +5 -0
index 770269c..5a91e5e 100644
@@ -1,3 +1,8 @@
+2014-03-17  Piotr Krysiuk  <[email protected]>
+
+     * grub-core/lib/i386/relocator.c: Moved GDT to end of physical memory
+     to avoid collision with old Linux BSS.
+
 2014-02-28  Vladimir Serbinenko  <[email protected]>
 
      * include/grub/i386/openbsd_bootarg.h: Add addr and frequency fields.
grub-core/lib/i386/relocator.c +1 -1
index d2a1b27..523f669 100644
@@ -84,7 +84,7 @@ grub_relocator32_boot (struct grub_relocator *rel,
   err = grub_relocator_alloc_chunk_align (rel, &ch, 0,
                                        (0xffffffff - RELOCATOR_SIZEOF (32))
                                        + 1, RELOCATOR_SIZEOF (32), 16,
-                                       GRUB_RELOCATOR_PREFERENCE_NONE,
+                                       GRUB_RELOCATOR_PREFERENCE_HIGH,
                                        avoid_efi_bootservices);
   if (err)
     return err;
Quoted 9 lines
Quoted 1 line

_______________________________________________
Grub-devel mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/grub-devel

script/lexer.c:321: token 259 text [
]
script/lexer.c:321: token 0 text []
script/lexer.c:321: token 288 text [linux]
script/lexer.c:321: token 289 text [(hd0)/vmlinuz]
script/lexer.c:321: token 259 text [
]
script/lexer.c:321: token 0 text []
lib/relocator.c:115: relocators_size=7
lib/relocator.c:1239: min_addr = 0x0, max_addr = 0xffffffff, target = 0x100000 lib/relocator.c:434: trying to allocate in 0x100000-0xffffffff aligned 0x1 size 0x1a9000 lib/relocator.c:1186: allocated: 0x100000+0x1a9000
lib/relocator.c:1275: allocated 0x100000/0x100000
lib/relocator.c:1293: relocators_size=7
lib/relocator.c:1301: relocators_size=7
lib/relocator.c:1308: cur = 0x3ff725c0, next = 0x0
loader/i386/linux.c:254: prot_mode_mem = 0x100000, prot_mode_target = 100000, prot_size = 1a9000 loader/i386/linux.c:878: bzImage, setup=0x1c00, size=0x1a8615
script/lexer.c:321: token 288 text [initrd]
script/lexer.c:321: token 289 text [(hd0)/initrd.gz]
script/lexer.c:321: token 259 text [
]
script/lexer.c:321: token 0 text []
lib/relocator.c:1385: chunks = 0x3ff725c0
lib/relocator.c:434: trying to allocate in 0x5fb000-0x37b75000 aligned 0x1000 size 0x47a430 lib/relocator.c:1186: allocated: 0x376fa000+0x47a430
lib/relocator.c:1397: allocated 0x376fa000/0x376fa000
lib/relocator.c:1398: chunks = 0x3ff725c0
loader/i386/linux.c:1124: Initrd, addr=0x37b75000, size=0x47a430
script/lexer.c:321: token 288 text [boot]
script/lexer.c:321: token 259 text [
]
script/lexer.c:321: token 0 text []
loader/i386/linux.c:570: real_size = 4000, mmap_size = 2000
loader/i386/linux.c:424: addr = 10000, size = 80000, need_size = 4000
loader/i386/linux.c:582: real_mode_target = 8c000, real_size = 4000, efi_mmap_size = 0 lib/relocator.c:1239: min_addr = 0x0, max_addr = 0x100000, target = 0x8c000 lib/relocator.c:434: trying to allocate in 0x2a9000-0xffffffff aligned 0x1 size 0x4000 lib/relocator.c:1186: allocated: 0x3f8559c0+0x4000
lib/relocator.c:1275: allocated 0x3f8559c0/0x8c000
lib/relocator.c:1293: relocators_size=7
lib/relocator.c:1301: relocators_size=29
lib/relocator.c:1308: cur = 0x3ff72af0, next = 0x3ff72700
loader/i386/linux.c:599: real_mode_mem = 0x3f8559c0
loader/i386/linux.c:609: code32_start = 100000
lib/relocator.c:1385: chunks = 0x3ff72af0
lib/relocator.c:434: trying to allocate in 0x1000-0x9ff31 aligned 0x10 size 0xd0 lib/relocator.c:1411: Adjusted limits from 1000-9ff31 to 0-100000
lib/relocator.c:434: trying to allocate in 0x0-0x100000 aligned 0x10 size 0xd0 lib/relocator.c:434: trying to allocate in 0x2a9000-0xffffffff aligned 0x1 size 0xd0 lib/relocator.c:1186: allocated: 0x3fff7c20+0xd0
lib/relocator.c:1466: relocators_size=29
lib/relocator.c:1474: relocators_size=51
lib/relocator.c:1480: cur = 0x3ff64750, next = 0x3ff72af0
grub_relocator32_boot: grub_relocator_alloc_chunk_align(..., GRUB_RELOCATOR_PREFERENCE_LOW,...) returned 3fff7c20 lib/relocator.c:1521: Preparing relocs (size=51)
lib/relocator.c:434: trying to allocate in 0x0-0xffffffcd aligned 0x1 size 0x33 lib/relocator.c:1186: allocated: 0x2a9000+0x33
lib/relocator.c:1533: Relocs allocated at 0x2a9000
lib/relocator.c:1548: chunk 0x3fff7c20->0x0, 0xd0
lib/relocator.c:1548: chunk 0x3f8559c0->0x8c000, 0x4000
lib/relocator.c:1548: chunk 0x376fa000->0x376fa000, 0x47a430
lib/relocator.c:1548: chunk 0x100000->0x100000, 0x1a9000
lib/relocator.c:1592: sorted chunk 0x100000->0x100000, 0x1a9000
lib/relocator.c:1592: sorted chunk 0x376fa000->0x376fa000, 0x47a430
lib/relocator.c:1592: sorted chunk 0x3f8559c0->0x8c000, 0x4000
lib/relocator.c:1592: sorted chunk 0x3fff7c20->0x0, 0xd0