1#
2# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3#
4# SPDX-License-Identifier: BSD-2-Clause
5#
6
7# This module provides a function GenerateSimulateScript which will place a `simulate`
8# script in the build directory for running produced images in Qemu.
9include_guard(GLOBAL)
10include("${KERNEL_HELPERS_PATH}")
11RequireFile(SIMULATE_SCRIPT simulate.py PATHS "${CMAKE_CURRENT_LIST_DIR}/../simulate_scripts/")
12RequireFile(GDB_SCRIPT launch_gdb.py PATHS "${CMAKE_CURRENT_LIST_DIR}/../simulate_scripts/")
13RequireFile(CONFIGURE_FILE_SCRIPT configure_file.cmake PATHS "${CMAKE_CURRENT_LIST_DIR}")
14
15# Help macro for testing a config and appending to a list that is destined for a qemu -cpu line
16macro(TestQemuCPUFeature config feature string)
17    if(${config})
18        set(${string} "${${string}},+${feature}")
19    else()
20        set(${string} "${${string}},-${feature}")
21    endif()
22endmacro(TestQemuCPUFeature)
23
24# Function for the user for configuration the simulation script. Valid values for property are
25#  'GRAPHIC' if set to TRUE disables the -nographic flag
26#  'MEM_SIZE' if set will override the memory size given to qemu
27function(SetSimulationScriptProperty property value)
28    # define the target if it doesn't already exist
29    if(NOT (TARGET simulation_script_prop_target))
30        add_custom_target(simulation_script_prop_target)
31    endif()
32    set_property(TARGET simulation_script_prop_target PROPERTY "${property}" "${value}")
33endfunction(SetSimulationScriptProperty)
34
35macro(SetDefaultMemSize default)
36    set(
37        QemuMemSize
38        "$<IF:$<BOOL:$<TARGET_PROPERTY:simulation_script_prop_target,MEM_SIZE>>,$<TARGET_PROPERTY:simulation_script_prop_target,MEM_SIZE>,${default}>"
39    )
40endmacro(SetDefaultMemSize)
41
42# Helper function that generates targets that will attempt to generate a ./simulate style script
43function(GenerateSimulateScript)
44    set(error "")
45    set(KERNEL_IMAGE_NAME "$<TARGET_PROPERTY:rootserver_image,KERNEL_IMAGE_NAME>")
46    set(IMAGE_NAME "$<TARGET_PROPERTY:rootserver_image,IMAGE_NAME>")
47    # Define simulation script target if it doesn't exist to simplify the generator expressions
48    if(NOT (TARGET simulation_script_prop_target))
49        add_custom_target(simulation_script_prop_target)
50    endif()
51    set(
52        sim_graphic_opt
53        "$<IF:$<BOOL:$<TARGET_PROPERTY:simulation_script_prop_target,GRAPHIC>>,,-nographic>"
54    )
55    set(sim_serial_opt "")
56    set(sim_cpu "")
57    set(sim_cpu_opt "")
58    set(sim_machine "")
59    set(qemu_sim_extra_args "")
60    if(KernelArchX86)
61        # Try and simulate the correct micro architecture and features
62        if(KernelX86MicroArchNehalem)
63            set(sim_cpu "Nehalem")
64        elseif(KernelX86MicroArchGeneric)
65            set(sim_cpu "qemu64")
66        elseif(KernelX86MicroArchWestmere)
67            set(sim_cpu "Westmere")
68        elseif(KernelX86MicroArchSandy)
69            set(sim_cpu "SandyBridge")
70        elseif(KernelX86MicroArchIvy)
71            set(sim_cpu "IvyBridge")
72        elseif(KernelX86MicroArchHaswell)
73            set(sim_cpu "Haswell")
74        elseif(KernelX86MicroArchBroadwell)
75            set(sim_cpu "Broadwell")
76        else()
77            set(error "Unknown x86 micro-architecture for simulation")
78        endif()
79        TestQemuCPUFeature(KernelVTX vme sim_cpu_opt)
80        TestQemuCPUFeature(KernelHugePage pdpe1gb sim_cpu_opt)
81        TestQemuCPUFeature(KernelFPUXSave xsave sim_cpu_opt)
82        TestQemuCPUFeature(KernelXSaveXSaveOpt xsaveopt sim_cpu_opt)
83        TestQemuCPUFeature(KernelXSaveXSaveC xsavec sim_cpu_opt)
84        TestQemuCPUFeature(KernelFSGSBaseInst fsgsbase sim_cpu_opt)
85        TestQemuCPUFeature(KernelSupportPCID invpcid sim_cpu_opt)
86        set(sim_cpu "${sim_cpu}")
87        set(sim_cpu_opt "${sim_cpu_opt},enforce")
88        set(QemuBinaryMachine "qemu-system-x86_64")
89        set(sim_serial_opt "-serial mon:stdio")
90        SetDefaultMemSize("512M")
91    elseif(KernelPlatformKZM)
92        set(QemuBinaryMachine "qemu-system-arm")
93        set(sim_machine "kzm")
94        SetDefaultMemSize("128M")
95    elseif(KernelPlatformSabre)
96        set(QemuBinaryMachine "qemu-system-arm")
97        # '-serial null -serial mon:stdio' means connect second UART to
98        # the terminal and ignore the first UART
99        set(sim_serial_opt "-serial null -serial mon:stdio")
100        set(sim_machine "sabrelite")
101        SetDefaultMemSize("1024M")
102    elseif(KernelPlatformZynq7000)
103        set(QemuBinaryMachine "qemu-system-arm")
104        set(sim_serial_opt "-serial null -serial mon:stdio")
105        set(sim_machine "xilinx-zynq-a9")
106        SetDefaultMemSize("1024M")
107    elseif(KernelPlatformWandQ)
108        set(QemuBinaryMachine "qemu-system-arm")
109        set(sim_serial_opt "-serial mon:stdio")
110        set(sim_machine "sabrelite")
111        SetDefaultMemSize("2048M")
112    elseif(KernelPlatformRpi3 AND KernelSel4ArchAarch64)
113        set(QemuBinaryMachine "qemu-system-aarch64")
114        set(sim_serial_opt "-serial null -serial mon:stdio")
115        set(sim_machine "raspi3")
116        SetDefaultMemSize("1024M")
117    elseif(KernelPlatformSpike)
118        if(KernelSel4ArchRiscV32)
119            set(binary "qemu-system-riscv32")
120            set(sim_cpu "rv32")
121            SetDefaultMemSize("2000M")
122            set(sim_machine "virt")
123        elseif(KernelSel4ArchRiscV64)
124            set(binary "qemu-system-riscv64")
125            set(sim_cpu "rv64")
126            SetDefaultMemSize("4095M")
127            set(sim_machine "spike")
128        endif()
129        set(QemuBinaryMachine "${binary}")
130        set(sim_serial_opt "-serial mon:stdio")
131        set(qemu_sim_extra_args "-bios none")
132    elseif(KernelPlatformQEMUArmVirt)
133        set(QemuBinaryMachine "qemu-system-${QEMU_ARCH}")
134        if(KernelArmHypervisorSupport)
135            set(sim_machine "virt,virtualization=on,highmem=off,secure=off")
136        else()
137            set(sim_machine "virt")
138        endif()
139        set(sim_graphic_opt "-nographic")
140        set(sim_cpu "${KernelArmCPU}")
141        SetDefaultMemSize("${QEMU_MEMORY}")
142    else()
143        set(error "Unsupported platform or architecture for simulation")
144    endif()
145    set(sim_path "${CMAKE_BINARY_DIR}/simulate")
146    set(gdb_path "${CMAKE_BINARY_DIR}/launch_gdb")
147    if(NOT "${error}" STREQUAL "")
148        set(script "#!/bin/sh\\necho ${error} && exit 1\\n")
149        add_custom_command(
150            OUTPUT "${sim_path}" "${gdb_path}"
151            COMMAND
152                printf "${script}" > "${sim_path}"
153            COMMAND
154                printf "${script}" > "${gdb_path}"
155            COMMAND
156                chmod u+x "${sim_path}" "${gdb_path}"
157            VERBATIM
158        )
159    else()
160        # We assume a x86 host, but will provide options to override the default gdb binary
161        if(KernelArchX86)
162            set(GdbBinary "gdb")
163        else()
164            set(GdbBinary "gdb-multiarch")
165        endif()
166        add_custom_command(
167            OUTPUT "${sim_path}"
168            COMMAND
169                ${CMAKE_COMMAND} -DCONFIGURE_INPUT_FILE=${SIMULATE_SCRIPT}
170                -DCONFIGURE_OUTPUT_FILE=${sim_path} -DQEMU_SIM_BINARY=${QemuBinaryMachine}
171                -DQEMU_SIM_CPU=${sim_cpu} -DQEMU_SIM_MACHINE=${sim_machine}
172                -DQEMU_SIM_CPU_OPT=${sim_cpu_opt} -DQEMU_SIM_GRAPHIC_OPT=${sim_graphic_opt}
173                -DQEMU_SIM_SERIAL_OPT=${sim_serial_opt} -DQEMU_SIM_MEM_SIZE_OPT=${QemuMemSize}
174                -DQEMU_SIM_KERNEL_FILE=${KERNEL_IMAGE_NAME} -DQEMU_SIM_INITRD_FILE=${IMAGE_NAME}
175                -DQEMU_SIM_EXTRA_ARGS=${qemu_sim_extra_args} -P ${CONFIGURE_FILE_SCRIPT}
176            COMMAND chmod u+x "${sim_path}"
177            VERBATIM COMMAND_EXPAND_LISTS
178        )
179        add_custom_command(
180            OUTPUT "${gdb_path}"
181            COMMAND
182                ${CMAKE_COMMAND} -DCONFIGURE_INPUT_FILE=${GDB_SCRIPT}
183                -DCONFIGURE_OUTPUT_FILE=${gdb_path} -DGDB_BINARY=${GdbBinary}
184                -DQEMU_SIM_KERNEL_FILE=${KERNEL_IMAGE_NAME} -DQEMU_SIM_INITRD_FILE=${IMAGE_NAME} -P
185                ${CONFIGURE_FILE_SCRIPT}
186            COMMAND chmod u+x "${gdb_path}"
187            VERBATIM COMMAND_EXPAND_LISTS
188        )
189    endif()
190    add_custom_target(simulate_gen ALL DEPENDS "${sim_path}")
191    add_custom_target(gdb_gen ALL DEPENDS "${gdb_path}")
192endfunction(GenerateSimulateScript)
193