Hello, our project uses various (micro)kernels booted via GRUB2 using the Multiboot & Multiboot2 protocol. Some of the kernels have several ELF segments which are not necessarily placed close together.
When booting such kernels with GRUB2 in BIOS legacy mode we observed that the screen shows colored blinking scrambled output, until the graphic drivers takes over. (Looks very fancy, but our customers don't like it ;-) ). We could track down the issue and have a fix for GRUB2, which is attached. Can you please have a look and check regarding what should/could be changed to get it upstream? We did not test the dynamic relocation part, since we have no such (kernel) setup. Thanks in advance. Regards, Alex. -- Alexander Boettcher Genode Labs http://www.genode-labs.com - http://www.genode.org - https://github.com/genodelabs/genode Genode Labs GmbH - Amtsgericht Dresden - HRB 28424 - Sitz Dresden Geschäftsführer: Dr.-Ing. Norman Feske, Christian Helmuth
From 605ca41045f97f92fb698ea49d7267e1cb29f40c Mon Sep 17 00:00:00 2001 From: Alexander Boettcher <alexander.boettc...@genode-labs.com> Date: Tue, 20 Mar 2018 09:21:06 +0100 Subject: [PATCH] multiboot: use per segment a separate relocator chunk If the segments are not dense packed, the original code set up a huge relocator chunk comprising all segments. During the final relocation in grub_relocator_prepare_relocs, the chunk is moved to its desired place and overrides memory which are actually not covered/touched by the specified segments. The overridden memory may contain reserved memory (vga text mode, acpi tables e.g.), which leads to strange boot behaviour. --- grub-core/loader/multiboot_elfxx.c | 59 +++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c index 67daf59..0d10c64 100644 --- a/grub-core/loader/multiboot_elfxx.c +++ b/grub-core/loader/multiboot_elfxx.c @@ -57,7 +57,7 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld) char *phdr_base; grub_err_t err; grub_relocator_chunk_t ch; - grub_uint32_t load_offset, load_size; + grub_uint32_t load_size; int i; void *source; @@ -99,29 +99,6 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld) load_size = highest_load - mld->link_base_addr; - if (mld->relocatable) - { - if (load_size > mld->max_addr || mld->min_addr > mld->max_addr - load_size) - return grub_error (GRUB_ERR_BAD_OS, "invalid min/max address and/or load size"); - - err = grub_relocator_alloc_chunk_align (GRUB_MULTIBOOT (relocator), &ch, - mld->min_addr, mld->max_addr - load_size, - load_size, mld->align ? mld->align : 1, - mld->preference, mld->avoid_efi_boot_services); - } - else - err = grub_relocator_alloc_chunk_addr (GRUB_MULTIBOOT (relocator), &ch, - mld->link_base_addr, load_size); - - if (err) - { - grub_dprintf ("multiboot_loader", "Cannot allocate memory for OS image\n"); - return err; - } - - mld->load_base_addr = get_physical_target_address (ch); - source = get_virtual_current_address (ch); - grub_dprintf ("multiboot_loader", "link_base_addr=0x%x, load_base_addr=0x%x, " "load_size=0x%x, relocatable=%d\n", mld->link_base_addr, mld->load_base_addr, load_size, mld->relocatable); @@ -133,21 +110,44 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld) /* Load every loadable segment in memory. */ for (i = 0; i < ehdr->e_phnum; i++) { - if (phdr(i)->p_type == PT_LOAD) + if (phdr(i)->p_type != PT_LOAD) + continue; + + if (mld->relocatable) { + if (load_size > mld->max_addr || mld->min_addr > mld->max_addr - load_size) + return grub_error (GRUB_ERR_BAD_OS, "invalid min/max address and/or load size"); + + err = grub_relocator_alloc_chunk_align (GRUB_MULTIBOOT (relocator), &ch, + mld->min_addr, mld->max_addr - load_size, + phdr(i)->p_memsz, mld->align ? mld->align : 1, + mld->preference, mld->avoid_efi_boot_services); + } else { + err = grub_relocator_alloc_chunk_addr (GRUB_MULTIBOOT (relocator), &ch, + phdr(i)->p_paddr, phdr(i)->p_memsz); + } + + if (err) + { + grub_dprintf ("multiboot_loader", "Cannot allocate memory for OS image\n"); + return err; + } + + if (mld->load_base_addr > get_physical_target_address (ch)) + mld->load_base_addr = get_physical_target_address (ch); + + source = get_virtual_current_address (ch); grub_dprintf ("multiboot_loader", "segment %d: paddr=0x%lx, memsz=0x%lx, vaddr=0x%lx\n", i, (long) phdr(i)->p_paddr, (long) phdr(i)->p_memsz, (long) phdr(i)->p_vaddr); - load_offset = phdr(i)->p_paddr - mld->link_base_addr; - if (phdr(i)->p_filesz != 0) { if (grub_file_seek (mld->file, (grub_off_t) phdr(i)->p_offset) == (grub_off_t) -1) return grub_errno; - if (grub_file_read (mld->file, (grub_uint8_t *) source + load_offset, phdr(i)->p_filesz) + if (grub_file_read (mld->file, (grub_uint8_t *) source, phdr(i)->p_filesz) != (grub_ssize_t) phdr(i)->p_filesz) { if (!grub_errno) @@ -158,9 +158,8 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld) } if (phdr(i)->p_filesz < phdr(i)->p_memsz) - grub_memset ((grub_uint8_t *) source + load_offset + phdr(i)->p_filesz, 0, + grub_memset ((grub_uint8_t *) source + phdr(i)->p_filesz, 0, phdr(i)->p_memsz - phdr(i)->p_filesz); - } } for (i = 0; i < ehdr->e_phnum; i++) -- 2.7.4
_______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel