# SPDX-License-Identifier: Apache-2.0 if("${ARCH}" STREQUAL "x86") set_ifndef(QEMU_binary_suffix i386) elseif(DEFINED QEMU_ARCH) set_ifndef(QEMU_binary_suffix ${QEMU_ARCH}) 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(CONFIG_BT_NO_DRIVER) set(NO_QEMU_SERIAL_BT_SERVER 1) endif() 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. For PPP, the serial port file is # not available if we run unit tests which define 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() elseif((CONFIG_NET_QEMU_PPP) AND NOT (CONFIG_NET_TEST)) set(QEMU_NET_STACK 1) 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(CONFIG_NET_QEMU_PPP) if(${CMAKE_GENERATOR} STREQUAL "Unix Makefiles") set(ppp_path unix:/tmp/ppp\${QEMU_INSTANCE}) else() set(ppp_path unix:/tmp/ppp${QEMU_INSTANCE}) endif() list(APPEND MORE_FLAGS_FOR_${target} -serial ${ppp_path} ) else() 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() 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_LONGMODE) # 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 COMMAND ${CMAKE_OBJCOPY} -O elf32-i386 $ ${CMAKE_BINARY_DIR}/zephyr-qemu.elf DEPENDS ${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() # Don't just test CONFIG_SMP, there is at least one test of the lower # level multiprocessor API that wants an auxiliary CPU but doesn't # want SMP using it. if(NOT CONFIG_MP_NUM_CPUS MATCHES "1") list(APPEND QEMU_SMP_FLAGS -smp cpus=${CONFIG_MP_NUM_CPUS}) 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;$") 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_SMP_FLAGS} ${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()