mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-08-15 11:55:22 +00:00
This patch adds a x86_64 architecture and qemu_x86_64 board to Zephyr. Only the basic architecture support needed to run 64 bit code is added; no drivers are added, though a low-level console exists and is wired to printk(). The support is built on top of a "X86 underkernel" layer, which can be built in isolation as a unit test on a Linux host. Limitations: + Right now the SDK lacks an x86_64 toolchain. The build will fall back to a host toolchain if it finds no cross compiler defined, which is tested to work on gcc 8.2.1 right now. + No x87/SSE/AVX usage is allowed. This is a stronger limitation than other architectures where the instructions work from one thread even if the context switch code doesn't support it. We are passing -no-sse to prevent gcc from automatically generating SSE instructions for non-floating-point purposes, which has the side effect of changing the ABI. Future work to handle the FPU registers will need to be combined with an "application" ABI distinct from the kernel one (or just to require USERSPACE). + Paging is enabled (it has to be in long mode), but is a 1:1 mapping of all memory. No MMU/USERSPACE support yet. + We are building with -mno-red-zone for stack size reasons, but this is a valuable optimization. Enabling it requires automatic stack switching, which requires a TSS, which means it has to happen after MMU support. + The OS runs in 64 bit mode, but for compatibility reasons is compiled to the 32 bit "X32" ABI. So while the full 64 bit registers and instruction set are available, C pointers are 32 bits long and Zephyr is constrained to run in the bottom 4G of memory. Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
267 lines
7.0 KiB
CMake
267 lines
7.0 KiB
CMake
if("${ARCH}" STREQUAL "x86")
|
|
set_ifndef(QEMU_binary_suffix i386)
|
|
else()
|
|
set_ifndef(QEMU_binary_suffix ${ARCH})
|
|
endif()
|
|
|
|
set(qemu_alternate_path $ENV{QEMU_BIN_PATH})
|
|
if(qemu_alternate_path)
|
|
find_program(
|
|
QEMU
|
|
PATHS ${qemu_alternate_path}
|
|
NO_DEFAULT_PATH
|
|
NAMES qemu-system-${QEMU_binary_suffix}
|
|
)
|
|
else()
|
|
find_program(
|
|
QEMU
|
|
qemu-system-${QEMU_binary_suffix}
|
|
)
|
|
endif()
|
|
|
|
set(qemu_targets
|
|
run
|
|
debugserver
|
|
)
|
|
|
|
set(QEMU_FLAGS -pidfile)
|
|
if(${CMAKE_GENERATOR} STREQUAL "Unix Makefiles")
|
|
list(APPEND QEMU_FLAGS qemu\${QEMU_INSTANCE}.pid)
|
|
else()
|
|
list(APPEND QEMU_FLAGS qemu${QEMU_INSTANCE}.pid)
|
|
endif()
|
|
|
|
# We can set "default" value for QEMU_PTY & QEMU_PIPE on cmake invocation.
|
|
if(QEMU_PTY)
|
|
# Send console output to a pseudo-tty, used for running automated tests
|
|
set(CMAKE_QEMU_SERIAL0 pty)
|
|
else()
|
|
if(QEMU_PIPE)
|
|
# Send console output to a pipe, used for running automated tests
|
|
set(CMAKE_QEMU_SERIAL0 pipe:${QEMU_PIPE})
|
|
else()
|
|
set(CMAKE_QEMU_SERIAL0 mon:stdio)
|
|
endif()
|
|
endif()
|
|
|
|
# But also can set QEMU_PTY & QEMU_PIPE on *make* (not cmake) invocation,
|
|
# like it was before cmake.
|
|
if(${CMAKE_GENERATOR} STREQUAL "Unix Makefiles")
|
|
list(APPEND QEMU_FLAGS
|
|
-serial
|
|
\${if \${QEMU_PTY}, pty, \${if \${QEMU_PIPE}, pipe:\${QEMU_PIPE}, ${CMAKE_QEMU_SERIAL0}}}
|
|
# NB: \$ is not supported by Ninja
|
|
)
|
|
else()
|
|
list(APPEND QEMU_FLAGS
|
|
-serial
|
|
${CMAKE_QEMU_SERIAL0}
|
|
)
|
|
endif()
|
|
|
|
# Add a BT serial device when building for bluetooth, unless the
|
|
# application explicitly opts out with NO_QEMU_SERIAL_BT_SERVER.
|
|
if(CONFIG_BT)
|
|
if(NOT NO_QEMU_SERIAL_BT_SERVER)
|
|
list(APPEND QEMU_FLAGS -serial unix:/tmp/bt-server-bredr)
|
|
endif()
|
|
endif()
|
|
|
|
# If we are running a networking application in QEMU, then set proper
|
|
# QEMU variables. This also allows two QEMUs to be hooked together and
|
|
# pass data between them. The QEMU flags are not set for standalone
|
|
# tests defined by CONFIG_NET_TEST.
|
|
if(CONFIG_NETWORKING)
|
|
if(CONFIG_NET_QEMU_SLIP)
|
|
if((CONFIG_NET_SLIP_TAP) OR (CONFIG_IEEE802154_UPIPE))
|
|
set(QEMU_NET_STACK 1)
|
|
endif()
|
|
endif()
|
|
endif()
|
|
|
|
# TO create independent pipes for each QEMU application set QEMU_PIPE_STACK
|
|
if(QEMU_PIPE_STACK)
|
|
list(APPEND qemu_targets
|
|
node
|
|
)
|
|
|
|
if(NOT QEMU_PIPE_ID)
|
|
set(QEMU_PIPE_ID 1)
|
|
endif()
|
|
|
|
list(APPEND QEMU_FLAGS
|
|
-serial none
|
|
)
|
|
|
|
list(APPEND MORE_FLAGS_FOR_node
|
|
-serial pipe:/tmp/hub/ip-stack-node${QEMU_PIPE_ID}
|
|
-pidfile qemu-node${QEMU_PIPE_ID}.pid
|
|
)
|
|
|
|
set(PIPE_NODE_IN /tmp/hub/ip-stack-node${QEMU_PIPE_ID}.in)
|
|
set(PIPE_NODE_OUT /tmp/hub/ip-stack-node${QEMU_PIPE_ID}.out)
|
|
|
|
set(pipes
|
|
${PIPE_NODE_IN}
|
|
${PIPE_NODE_OUT}
|
|
)
|
|
|
|
set(destroy_pipe_commands
|
|
COMMAND ${CMAKE_COMMAND} -E remove -f ${pipes}
|
|
)
|
|
|
|
set(create_pipe_commands
|
|
COMMAND ${CMAKE_COMMAND} -E make_directory /tmp/hub
|
|
COMMAND mkfifo ${PIPE_NODE_IN}
|
|
COMMAND mkfifo ${PIPE_NODE_OUT}
|
|
)
|
|
|
|
set(PRE_QEMU_COMMANDS_FOR_node
|
|
${destroy_pipe_commands}
|
|
${create_pipe_commands}
|
|
)
|
|
|
|
elseif(QEMU_NET_STACK)
|
|
list(APPEND qemu_targets
|
|
client
|
|
server
|
|
)
|
|
|
|
foreach(target ${qemu_targets})
|
|
if((${target} STREQUAL client) OR (${target} STREQUAL server))
|
|
list(APPEND MORE_FLAGS_FOR_${target}
|
|
-serial pipe:/tmp/ip-stack-${target}
|
|
-pidfile qemu-${target}.pid
|
|
)
|
|
else()
|
|
# QEMU_INSTANCE is a command line argument to *make* (not cmake). By
|
|
# appending the instance name to the pid file we can easily run more
|
|
# instances of the same sample.
|
|
|
|
if(${CMAKE_GENERATOR} STREQUAL "Unix Makefiles")
|
|
set(tmp_file unix:/tmp/slip.sock\${QEMU_INSTANCE})
|
|
else()
|
|
set(tmp_file unix:/tmp/slip.sock${QEMU_INSTANCE})
|
|
endif()
|
|
|
|
list(APPEND MORE_FLAGS_FOR_${target}
|
|
-serial ${tmp_file}
|
|
)
|
|
endif()
|
|
endforeach()
|
|
|
|
|
|
set(PIPE_SERVER_IN /tmp/ip-stack-server.in)
|
|
set(PIPE_SERVER_OUT /tmp/ip-stack-server.out)
|
|
set(PIPE_CLIENT_IN /tmp/ip-stack-client.in)
|
|
set(PIPE_CLIENT_OUT /tmp/ip-stack-client.out)
|
|
|
|
set(pipes
|
|
${PIPE_SERVER_IN}
|
|
${PIPE_SERVER_OUT}
|
|
${PIPE_CLIENT_IN}
|
|
${PIPE_CLIENT_OUT}
|
|
)
|
|
|
|
set(destroy_pipe_commands
|
|
COMMAND ${CMAKE_COMMAND} -E remove -f ${pipes}
|
|
)
|
|
|
|
# TODO: Port to Windows. Perhaps using python? Or removing the
|
|
# need for mkfifo and create_symlink somehow.
|
|
set(create_pipe_commands
|
|
COMMAND mkfifo ${PIPE_SERVER_IN}
|
|
COMMAND mkfifo ${PIPE_SERVER_OUT}
|
|
)
|
|
if(PCAP)
|
|
list(APPEND create_pipe_commands
|
|
COMMAND mkfifo ${PIPE_CLIENT_IN}
|
|
COMMAND mkfifo ${PIPE_CLIENT_OUT}
|
|
)
|
|
else()
|
|
list(APPEND create_pipe_commands
|
|
COMMAND ${CMAKE_COMMAND} -E create_symlink ${PIPE_SERVER_IN} ${PIPE_CLIENT_OUT}
|
|
COMMAND ${CMAKE_COMMAND} -E create_symlink ${PIPE_SERVER_OUT} ${PIPE_CLIENT_IN}
|
|
)
|
|
endif()
|
|
|
|
set(PRE_QEMU_COMMANDS_FOR_server
|
|
${destroy_pipe_commands}
|
|
${create_pipe_commands}
|
|
)
|
|
if(PCAP)
|
|
# Start a monitor application to capture traffic
|
|
#
|
|
# Assumes;
|
|
# PCAP has been set to the file where traffic should be captured
|
|
# NET_TOOLS has been set to the net-tools repo path
|
|
# net-tools/monitor_15_4 has been built beforehand
|
|
|
|
set_ifndef(NET_TOOLS ${ZEPHYR_BASE}/../net-tools) # Default if not set
|
|
|
|
list(APPEND PRE_QEMU_COMMANDS_FOR_server
|
|
COMMAND ${NET_TOOLS}/monitor_15_4
|
|
${PCAP}
|
|
/tmp/ip-stack-server
|
|
/tmp/ip-stack-client
|
|
> /dev/null &
|
|
# TODO: Support cleanup of the monitor_15_4 process
|
|
)
|
|
endif()
|
|
endif(QEMU_PIPE_STACK)
|
|
|
|
if(CONFIG_X86_IAMCU)
|
|
list(APPEND PRE_QEMU_COMMANDS
|
|
COMMAND
|
|
${PYTHON_EXECUTABLE}
|
|
${ZEPHYR_BASE}/scripts/qemu-machine-hack.py
|
|
$<TARGET_FILE:${logical_target_for_zephyr_elf}>
|
|
)
|
|
endif()
|
|
|
|
if(CONFIG_X86_64)
|
|
set(QEMU_KERNEL_FILE "${CMAKE_BINARY_DIR}/zephyr-qemu.elf")
|
|
endif()
|
|
|
|
if(NOT QEMU_PIPE)
|
|
set(QEMU_PIPE_COMMENT "\nTo exit from QEMU enter: 'CTRL+a, x'\n")
|
|
endif()
|
|
|
|
# Use flags passed in from the environment
|
|
set(env_qemu $ENV{QEMU_EXTRA_FLAGS})
|
|
separate_arguments(env_qemu)
|
|
list(APPEND QEMU_EXTRA_FLAGS ${env_qemu})
|
|
|
|
list(APPEND MORE_FLAGS_FOR_debugserver -s -S)
|
|
|
|
# Architectures can define QEMU_KERNEL_FILE to use a specific output
|
|
# file to pass to qemu (and a "qemu_kernel_target" target to generate
|
|
# it), or set QEMU_KERNEL_OPTION if they want to replace the "-kernel
|
|
# ..." option entirely.
|
|
if(DEFINED QEMU_KERNEL_FILE)
|
|
set(QEMU_KERNEL_OPTION "-kernel;${QEMU_KERNEL_FILE}")
|
|
elseif(NOT DEFINED QEMU_KERNEL_OPTION)
|
|
set(QEMU_KERNEL_OPTION "-kernel;$<TARGET_FILE:${logical_target_for_zephyr_elf}>")
|
|
endif()
|
|
|
|
foreach(target ${qemu_targets})
|
|
add_custom_target(${target}
|
|
${PRE_QEMU_COMMANDS}
|
|
${PRE_QEMU_COMMANDS_FOR_${target}}
|
|
COMMAND
|
|
${QEMU}
|
|
${QEMU_FLAGS_${ARCH}}
|
|
${QEMU_FLAGS}
|
|
${QEMU_EXTRA_FLAGS}
|
|
${MORE_FLAGS_FOR_${target}}
|
|
${QEMU_KERNEL_OPTION}
|
|
DEPENDS ${logical_target_for_zephyr_elf}
|
|
WORKING_DIRECTORY ${APPLICATION_BINARY_DIR}
|
|
COMMENT "${QEMU_PIPE_COMMENT}[QEMU] CPU: ${QEMU_CPU_TYPE_${ARCH}}"
|
|
USES_TERMINAL
|
|
)
|
|
if(DEFINED QEMU_KERNEL_FILE)
|
|
add_dependencies(${target} qemu_kernel_target)
|
|
endif()
|
|
endforeach()
|