Re: [Qemu-devel] [RFC/PoC PATCH 1/3] i386: set initrd_max to 4G - 1 to allow up to 4G initrd

From: Li Zhijian
Date: Fri Nov 09 2018 - 04:58:01 EST


On 11/9/2018 3:20 PM, Ingo Molnar wrote:
* Li Zhijian <lizhijian@xxxxxxxxxxxxxx> wrote:

If the kernel initrd creation process creates an initrd which
is larger than 2GB and also claims that it can't be placed
with any part of it above 2GB, then that sounds like a bug
in the initrd creation process...
Exactly, it's a real problem.

Add x86 maintainers and LKML:

The background is that QEMU want to support up to 4G initrd. but linux header (
initrd_addr_max field) only allow 2G-1.
Is one of the below approaches reasonable:
1) change initrd_addr_max to 4G-1 directly simply(arch/x86/boot/header.S)?
2) lie QEMU bootloader the initrd_addr_max is 4G-1 even though header said 2G-1
3) any else
A 10 years old comment from hpa says:

initrd_addr_max: .long 0x7fffffff
# (Header version 0x0203 or later)
# The highest safe address for
# the contents of an initrd
# The current kernel allows up to 4 GB,
# but leave it at 2 GB to avoid
# possible bootloader bugs.

To avoid the potential of bugs lurking in dozens of major and hundreds of
minor iterations of various Linux bootloaders I'd prefer a real solution
and extend it - because if there's a 2GB initrd for some weird reason
today there might be a 4GB one in two years.

thank a lots. that's amazing.



The real solution would be to:

- Extend the boot protocol with a 64-bit field, named initrd_addr64_max
or such.
- We don't change the old field - but if the new field is set by new
kernels then new bootloaders can use that as a new initrd_addr64_max
value. (or reject to load the kernel if the address is too high.)

- The kernel build should also emit a warning when building larger than
2GB initrds, with a list of bootloaders that support the new protocol.

Actually i just knew QEMU(Seabios + optionrom(linuxboot_dma.bin)) can support ~4GB initrd so far.

i just drafted at patch to add this field. could you have a look.
another patch which is to document initrd_addr64_max is ongoing.

commit db463ac9c1975f115d1ce2acb82d530c2b63b888
Author: Li Zhijian <lizhijian@xxxxxxxxxxxxxx>
Date: Fri Nov 9 17:24:14 2018 +0800

x86: Add header field initrd_addr64_max
Years ago, kernel had support load ~4GB initrd. But for some weird reasons (
avoid possible bootloader bugs), it only allow leave initrd under 2GB address
space(see initrd_addr_max fild at arch/x86/boot/header.S).
So modern bootloaders have not chance to load >=2G initrd previously.
To avoid the potential of bugs lurking in dozens of major and hundreds of
minor iterations of various Linux bootloaders. Ingo suggests to add a new field
initrd_addr64_max. If bootloader believes that it can load initrd to >=2G
address space, it can use initrd_addr64_max as the maximum loading address in
stead of the old field initrd_addr_max.

diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index 4c881c8..5fc3ebe 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -300,7 +300,7 @@ _start:
# Part 2 of the header, from the old setup.S
.ascii "HdrS" # header signature
- .word 0x020e # header version number (>= 0x0105)
+ .word 0x020f # header version number (>= 0x0105)
# or else old loadlin-1.5 will fail)
.globl realmode_swtch
realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
@@ -562,6 +562,12 @@ acpi_rsdp_addr: .quad 0 # 64-bit physical pointer to the
# ACPI RSDP table, added with
# version 2.14
+#ifdef CONFIG_INITRD_SIZE_4GB
+initrd_addr64_max: .quad 0xffffffff # allow ~4G initrd since 2.15
+#else
+initrd_addr64_max: .quad 0
+#endif
+
# End of setup header #####################################################
.section ".entrytext", "ax"
diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
index 22f89d0..b86013d 100644
--- a/arch/x86/include/uapi/asm/bootparam.h
+++ b/arch/x86/include/uapi/asm/bootparam.h
@@ -90,6 +90,7 @@ struct setup_header {
__u32 init_size;
__u32 handover_offset;
__u64 acpi_rsdp_addr;
+ __u64 initrd_addr64_max;
} __attribute__((packed));
struct sys_desc_table {
diff --git a/init/Kconfig b/init/Kconfig
index a4112e9..611d4af 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1080,6 +1080,14 @@ config BLK_DEV_INITRD
If unsure say Y.
+config INITRD_SIZE_4GB
+ bool "4G size initrd support"
+ depends on (X86 || X86_64)
+ help
+ This option enables support ~4GB initrd.
+
+ if unsure say N.
+
if BLK_DEV_INITRD
source "usr/Kconfig"

Thanks
Zhijian




Or something along those lines.

Thanks,

Ingo