The setup block contains the real mode startup code that is used when booting from a legacy BIOS, along with the boot_params/setup_data that is used by legacy x86 bootloaders to pass the command line and initial ramdisk parameters, among other things. The setup block also contains the PE/COFF header of the entire combined image, which includes the compressed kernel image, the decompressor and the EFI stub. This PE header describes the layout of the executable image in memory, and currently, the fact that the setup block precedes it makes it rather fiddly to get the right values into the right place in the final image. One complicating factor here is the variable setup block size, and given that we will need to round up the setup block size to page size anyway in a subsequent patch (in order to be able to use different permissions for .text and .data), let's round it up to a fixed size of 16 KiB and be done with it. Note that Clang does not optimize for size as aggressively as GCC when using the -Os option, but it supports -Oz for this purpose, so pass that if the compiler supports it. Signed-off-by: Ard Biesheuvel <ardb@xxxxxxxxxx> --- arch/x86/boot/Makefile | 1 + arch/x86/boot/header.S | 6 +++++- arch/x86/boot/setup.ld | 1 + arch/x86/boot/tools/build.c | 12 +++++------- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile index 0e98bc5036994715..be1e8b94c93afa4a 100644 --- a/arch/x86/boot/Makefile +++ b/arch/x86/boot/Makefile @@ -69,6 +69,7 @@ KBUILD_CFLAGS := $(REALMODE_CFLAGS) -D_SETUP KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ KBUILD_CFLAGS += $(call cc-option,-fmacro-prefix-map=$(srctree)/=) KBUILD_CFLAGS += -fno-asynchronous-unwind-tables +KBUILD_CFLAGS += $(call cc-option,-Oz) GCOV_PROFILE := n UBSAN_SANITIZE := n diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S index 72744ba440f6ea09..bef9265173757a5a 100644 --- a/arch/x86/boot/header.S +++ b/arch/x86/boot/header.S @@ -36,6 +36,10 @@ SYSSEG = 0x1000 /* historical load address >> 4 */ #define ROOT_RDONLY 1 #endif + /* The setup block has a fixed size: 32 * 512 == 16k */ + .globl setup_size + .set setup_size, 0x4000 + .code16 .section ".bstext", "ax" #ifdef CONFIG_EFI_STUB @@ -231,7 +235,7 @@ sentinel: .byte 0xff, 0xff /* Used to detect broken loaders */ .globl hdr hdr: -setup_sects: .byte 0 /* Filled in by build.c */ +setup_sects: .byte (setup_size / 512) - 1 root_flags: .word ROOT_RDONLY syssize: .long 0 /* Filled in by build.c */ ram_size: .word 0 /* Obsolete */ diff --git a/arch/x86/boot/setup.ld b/arch/x86/boot/setup.ld index a05dcaa4b74cd9f8..f1c14616cd80390d 100644 --- a/arch/x86/boot/setup.ld +++ b/arch/x86/boot/setup.ld @@ -57,6 +57,7 @@ SECTIONS } ASSERT(_end <= 0x8000, "Setup too big!") + ASSERT(__bss_start <= setup_size, "Setup image size too big!") ASSERT(hdr == 0x1f1, "The setup header has the wrong offset!") /* Necessary for the very-old-loader check to work... */ ASSERT(__end_init <= 5*512, "init sections too big!") diff --git a/arch/x86/boot/tools/build.c b/arch/x86/boot/tools/build.c index 06949754316458ce..665ce7241542e475 100644 --- a/arch/x86/boot/tools/build.c +++ b/arch/x86/boot/tools/build.c @@ -40,12 +40,10 @@ typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; -/* Minimal number of setup sectors */ -#define SETUP_SECT_MIN 5 -#define SETUP_SECT_MAX 64 +#define SETUP_SECT_NUM 32 /* This must be large enough to hold the entire setup */ -u8 buf[SETUP_SECT_MAX*512]; +u8 buf[(SETUP_SECT_NUM+1)*512]; #define PECOFF_RELOC_RESERVE 0x20 @@ -360,8 +358,9 @@ int main(int argc, char ** argv) /* Pad unused space with zeros */ setup_sectors = (c + 511) / 512; - if (setup_sectors < SETUP_SECT_MIN) - setup_sectors = SETUP_SECT_MIN; + if (setup_sectors > SETUP_SECT_NUM) + die("setup size exceeds maximum"); + setup_sectors = SETUP_SECT_NUM; i = setup_sectors*512; memset(buf+c, 0, i-c); @@ -388,7 +387,6 @@ int main(int argc, char ** argv) #endif /* Patch the setup code with the appropriate size parameters */ - buf[0x1f1] = setup_sectors-1; put_unaligned_le32(sys_size, &buf[0x1f4]); update_pecoff_text(setup_sectors * 512, i + (sys_size * 16)); -- 2.39.2