Unable to boot very old Linux kernels
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
@@ -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
@@ -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
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@@ -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@@ -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;
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 aligned0x10 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
@@ -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#n57Quoted 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@@ -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@@ -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
[H[J[1;1Hscript/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=7lib/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+0x1a9000lib/relocator.c:1275: allocated 0x100000/0x100000lib/relocator.c:1293: relocators_size=7lib/relocator.c:1301: relocators_size=7lib/relocator.c:1308: cur = 0x3ff725c0, next = 0x0loader/i386/linux.c:254: prot_mode_mem = 0x100000, prot_mode_target = 100000, prot_size = 1a9000 loader/i386/linux.c:878: bzImage, setup=0x1c00, size=0x1a8615script/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 = 0x3ff725c0lib/relocator.c:434: trying to allocate in 0x5fb000-0x37b75000 aligned 0x1000 size 0x47a430 lib/relocator.c:1186: allocated: 0x376fa000+0x47a430lib/relocator.c:1397: allocated 0x376fa000/0x376fa000lib/relocator.c:1398: chunks = 0x3ff725c0loader/i386/linux.c:1124: Initrd, addr=0x37b75000, size=0x47a430script/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 = 2000loader/i386/linux.c:424: addr = 10000, size = 80000, need_size = 4000loader/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+0x4000lib/relocator.c:1275: allocated 0x3f8559c0/0x8c000lib/relocator.c:1293: relocators_size=7lib/relocator.c:1301: relocators_size=29lib/relocator.c:1308: cur = 0x3ff72af0, next = 0x3ff72700loader/i386/linux.c:599: real_mode_mem = 0x3f8559c0loader/i386/linux.c:609: code32_start = 100000lib/relocator.c:1385: chunks = 0x3ff72af0lib/relocator.c:434: trying to allocate in 0x1000-0x9ff31 aligned 0x10 size 0xd0 lib/relocator.c:1411: Adjusted limits from 1000-9ff31 to 0-100000lib/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+0xd0lib/relocator.c:1466: relocators_size=29lib/relocator.c:1474: relocators_size=51lib/relocator.c:1480: cur = 0x3ff64750, next = 0x3ff72af0grub_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+0x33lib/relocator.c:1533: Relocs allocated at 0x2a9000lib/relocator.c:1548: chunk 0x3fff7c20->0x0, 0xd0lib/relocator.c:1548: chunk 0x3f8559c0->0x8c000, 0x4000lib/relocator.c:1548: chunk 0x376fa000->0x376fa000, 0x47a430lib/relocator.c:1548: chunk 0x100000->0x100000, 0x1a9000lib/relocator.c:1592: sorted chunk 0x100000->0x100000, 0x1a9000lib/relocator.c:1592: sorted chunk 0x376fa000->0x376fa000, 0x47a430lib/relocator.c:1592: sorted chunk 0x3f8559c0->0x8c000, 0x4000lib/relocator.c:1592: sorted chunk 0x3fff7c20->0x0, 0xd0
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 aligned0x10 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
@@ -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#n57Quoted 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@@ -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@@ -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
[H[J[1;1Hscript/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=7lib/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+0x1a9000lib/relocator.c:1275: allocated 0x100000/0x100000lib/relocator.c:1293: relocators_size=7lib/relocator.c:1301: relocators_size=7lib/relocator.c:1308: cur = 0x3ff725c0, next = 0x0loader/i386/linux.c:254: prot_mode_mem = 0x100000, prot_mode_target = 100000, prot_size = 1a9000 loader/i386/linux.c:878: bzImage, setup=0x1c00, size=0x1a8615script/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 = 0x3ff725c0lib/relocator.c:434: trying to allocate in 0x5fb000-0x37b75000 aligned 0x1000 size 0x47a430 lib/relocator.c:1186: allocated: 0x376fa000+0x47a430lib/relocator.c:1397: allocated 0x376fa000/0x376fa000lib/relocator.c:1398: chunks = 0x3ff725c0loader/i386/linux.c:1124: Initrd, addr=0x37b75000, size=0x47a430script/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 = 2000loader/i386/linux.c:424: addr = 10000, size = 80000, need_size = 4000loader/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+0x4000lib/relocator.c:1275: allocated 0x3f8559c0/0x8c000lib/relocator.c:1293: relocators_size=7lib/relocator.c:1301: relocators_size=29lib/relocator.c:1308: cur = 0x3ff72af0, next = 0x3ff72700loader/i386/linux.c:599: real_mode_mem = 0x3f8559c0loader/i386/linux.c:609: code32_start = 100000lib/relocator.c:1385: chunks = 0x3ff72af0lib/relocator.c:434: trying to allocate in 0x1000-0x9ff31 aligned 0x10 size 0xd0 lib/relocator.c:1411: Adjusted limits from 1000-9ff31 to 0-100000lib/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+0xd0lib/relocator.c:1466: relocators_size=29lib/relocator.c:1474: relocators_size=51lib/relocator.c:1480: cur = 0x3ff64750, next = 0x3ff72af0grub_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+0x33lib/relocator.c:1533: Relocs allocated at 0x2a9000lib/relocator.c:1548: chunk 0x3fff7c20->0x0, 0xd0lib/relocator.c:1548: chunk 0x3f8559c0->0x8c000, 0x4000lib/relocator.c:1548: chunk 0x376fa000->0x376fa000, 0x47a430lib/relocator.c:1548: chunk 0x100000->0x100000, 0x1a9000lib/relocator.c:1592: sorted chunk 0x100000->0x100000, 0x1a9000lib/relocator.c:1592: sorted chunk 0x376fa000->0x376fa000, 0x47a430lib/relocator.c:1592: sorted chunk 0x3f8559c0->0x8c000, 0x4000lib/relocator.c:1592: sorted chunk 0x3fff7c20->0x0, 0xd0
Quoted 2 lines · Piotras
This fails to allocate from low memory and falls back to top of physical memory, ignoring preference.
Likely you mistook temporary location of chunk with permanent address. Chunks are moved right before boot.