From 04e874485bebbe26c63204a957e5534152e60dea Mon Sep 17 00:00:00 2001 From: Stephanos Ioannidis Date: Tue, 7 Jan 2020 15:35:15 +0900 Subject: [PATCH] x86: intel64: Split 'locore' and 'main' kernel images for QEMU This commit splits the 'locore' and 'main' memory regions into separate executable images and specifies the 'locore' as the boot kernel, in order to prevent the QEMU direct multiboot kernel loader from overwriting the BIOS and option ROM areas located in between the two memory regions. The Zephyr x86-64 kernel image consists of two discontiguous load memory regions: 'locore' at 0x8000 and 'main' at 0x100000, but the QEMU treats these as single contiguous memory region starting at 0x8000 and ending at (0x100000 + MAIN_IMAGE_SIZE - 1). This results in the direct multiboot kernel loader overwriting the BIOS and option ROM areas as part of the kernel loading process, and causes any writable system regions to be corrupted (e.g. KVMVAPIC ROM). By splitting the two discontiguous memory regions into separate images and specifying only the boot image (i.e. 'locore') as the '-kernel', it is possible to work around the QEMU direct kernel loading design limitation. This workaround is required to support the QEMU v4.2.0 and above. For more details, refer to the issue zephyrproject-rtos/sdk-ng#168. Signed-off-by: Stephanos Ioannidis --- cmake/emu/qemu.cmake | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/cmake/emu/qemu.cmake b/cmake/emu/qemu.cmake index 4b2cceb50fe..2378927a25b 100644 --- a/cmake/emu/qemu.cmake +++ b/cmake/emu/qemu.cmake @@ -226,8 +226,7 @@ endif(QEMU_PIPE_STACK) if(CONFIG_X86_64) # QEMU doesn't like 64-bit ELF files. Since we don't use any >4GB # addresses, converting it to 32-bit is safe enough for emulation. - set(QEMU_KERNEL_FILE "${CMAKE_BINARY_DIR}/zephyr-qemu.elf") - add_custom_target(qemu_kernel_target + add_custom_target(qemu_image_target COMMAND ${CMAKE_OBJCOPY} -O elf32-i386 @@ -235,6 +234,42 @@ if(CONFIG_X86_64) ${CMAKE_BINARY_DIR}/zephyr-qemu.elf DEPENDS ${logical_target_for_zephyr_elf} ) + + # Split the 'locore' and 'main' memory regions into separate executable + # images and specify the 'locore' as the boot kernel, in order to prevent + # the QEMU direct multiboot kernel loader from overwriting the BIOS and + # option ROM areas located in between the two memory regions. + # (for more details, refer to the issue zephyrproject-rtos/sdk-ng#168) + add_custom_target(qemu_locore_image_target + COMMAND + ${CMAKE_OBJCOPY} + -j .locore + ${CMAKE_BINARY_DIR}/zephyr-qemu.elf + ${CMAKE_BINARY_DIR}/zephyr-qemu-locore.elf + 2>&1 | grep -iv \"empty loadable segment detected\" || true + DEPENDS qemu_image_target + ) + + add_custom_target(qemu_main_image_target + COMMAND + ${CMAKE_OBJCOPY} + -R .locore + ${CMAKE_BINARY_DIR}/zephyr-qemu.elf + ${CMAKE_BINARY_DIR}/zephyr-qemu-main.elf + 2>&1 | grep -iv \"empty loadable segment detected\" || true + DEPENDS qemu_image_target + ) + + add_custom_target( + qemu_kernel_target + DEPENDS qemu_locore_image_target qemu_main_image_target + ) + + set(QEMU_KERNEL_FILE "${CMAKE_BINARY_DIR}/zephyr-qemu-locore.elf") + + list(APPEND QEMU_EXTRA_FLAGS + "-device;loader,file=${CMAKE_BINARY_DIR}/zephyr-qemu-main.elf" + ) endif() if(NOT QEMU_PIPE)