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 <root@stephanos.io>
This commit is contained in:
Stephanos Ioannidis 2020-01-07 15:35:15 +09:00 committed by Kumar Gala
commit 04e874485b

View file

@ -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)