vmtest.sh 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. #!/bin/bash
  2. # SPDX-License-Identifier: GPL-2.0
  3. set -u
  4. set -e
  5. # This script currently only works for x86_64
  6. ARCH="$(uname -m)"
  7. case "${ARCH}" in
  8. x86_64)
  9. QEMU_BINARY=qemu-system-x86_64
  10. BZIMAGE="arch/x86/boot/bzImage"
  11. ;;
  12. *)
  13. echo "Unsupported architecture"
  14. exit 1
  15. ;;
  16. esac
  17. SCRIPT_DIR="$(dirname $(realpath $0))"
  18. OUTPUT_DIR="$SCRIPT_DIR/results"
  19. KCONFIG_REL_PATHS=("${SCRIPT_DIR}/config" "${SCRIPT_DIR}/config.common" "${SCRIPT_DIR}/config.${ARCH}")
  20. B2C_URL="https://gitlab.freedesktop.org/gfx-ci/boot2container/-/raw/main/vm2c.py"
  21. NUM_COMPILE_JOBS="$(nproc)"
  22. LOG_FILE_BASE="$(date +"hid_selftests.%Y-%m-%d_%H-%M-%S")"
  23. LOG_FILE="${LOG_FILE_BASE}.log"
  24. EXIT_STATUS_FILE="${LOG_FILE_BASE}.exit_status"
  25. CONTAINER_IMAGE="registry.freedesktop.org/bentiss/hid/fedora/39:2023-11-22.1"
  26. TARGETS="${TARGETS:=$(basename ${SCRIPT_DIR})}"
  27. DEFAULT_COMMAND="pip3 install hid-tools; make -C tools/testing/selftests TARGETS=${TARGETS} run_tests"
  28. usage()
  29. {
  30. cat <<EOF
  31. Usage: $0 [-j N] [-s] [-b] [-d <output_dir>] -- [<command>]
  32. <command> is the command you would normally run when you are in
  33. the source kernel direcory. e.g:
  34. $0 -- ./tools/testing/selftests/hid/hid_bpf
  35. If no command is specified and a debug shell (-s) is not requested,
  36. "${DEFAULT_COMMAND}" will be run by default.
  37. If you build your kernel using KBUILD_OUTPUT= or O= options, these
  38. can be passed as environment variables to the script:
  39. O=<kernel_build_path> $0 -- ./tools/testing/selftests/hid/hid_bpf
  40. or
  41. KBUILD_OUTPUT=<kernel_build_path> $0 -- ./tools/testing/selftests/hid/hid_bpf
  42. Options:
  43. -u) Update the boot2container script to a newer version.
  44. -d) Update the output directory (default: ${OUTPUT_DIR})
  45. -b) Run only the build steps for the kernel and the selftests
  46. -j) Number of jobs for compilation, similar to -j in make
  47. (default: ${NUM_COMPILE_JOBS})
  48. -s) Instead of powering off the VM, start an interactive
  49. shell. If <command> is specified, the shell runs after
  50. the command finishes executing
  51. EOF
  52. }
  53. download()
  54. {
  55. local file="$1"
  56. echo "Downloading $file..." >&2
  57. curl -Lsf "$file" -o "${@:2}"
  58. }
  59. recompile_kernel()
  60. {
  61. local kernel_checkout="$1"
  62. local make_command="$2"
  63. cd "${kernel_checkout}"
  64. ${make_command} olddefconfig
  65. ${make_command} headers
  66. ${make_command}
  67. }
  68. update_selftests()
  69. {
  70. local kernel_checkout="$1"
  71. local selftests_dir="${kernel_checkout}/tools/testing/selftests/hid"
  72. cd "${selftests_dir}"
  73. ${make_command}
  74. }
  75. run_vm()
  76. {
  77. local run_dir="$1"
  78. local b2c="$2"
  79. local kernel_bzimage="$3"
  80. local command="$4"
  81. local post_command=""
  82. cd "${run_dir}"
  83. if ! which "${QEMU_BINARY}" &> /dev/null; then
  84. cat <<EOF
  85. Could not find ${QEMU_BINARY}
  86. Please install qemu or set the QEMU_BINARY environment variable.
  87. EOF
  88. exit 1
  89. fi
  90. # alpine (used in post-container requires the PATH to have /bin
  91. export PATH=$PATH:/bin
  92. if [[ "${debug_shell}" != "yes" ]]
  93. then
  94. touch ${OUTPUT_DIR}/${LOG_FILE}
  95. command="mount bpffs -t bpf /sys/fs/bpf/; set -o pipefail ; ${command} 2>&1 | tee ${OUTPUT_DIR}/${LOG_FILE}"
  96. post_command="cat ${OUTPUT_DIR}/${LOG_FILE}"
  97. else
  98. command="mount bpffs -t bpf /sys/fs/bpf/; ${command}"
  99. fi
  100. set +e
  101. $b2c --command "${command}" \
  102. --kernel ${kernel_bzimage} \
  103. --workdir ${OUTPUT_DIR} \
  104. --image ${CONTAINER_IMAGE}
  105. echo $? > ${OUTPUT_DIR}/${EXIT_STATUS_FILE}
  106. set -e
  107. ${post_command}
  108. }
  109. is_rel_path()
  110. {
  111. local path="$1"
  112. [[ ${path:0:1} != "/" ]]
  113. }
  114. do_update_kconfig()
  115. {
  116. local kernel_checkout="$1"
  117. local kconfig_file="$2"
  118. rm -f "$kconfig_file" 2> /dev/null
  119. for config in "${KCONFIG_REL_PATHS[@]}"; do
  120. local kconfig_src="${config}"
  121. cat "$kconfig_src" >> "$kconfig_file"
  122. done
  123. }
  124. update_kconfig()
  125. {
  126. local kernel_checkout="$1"
  127. local kconfig_file="$2"
  128. if [[ -f "${kconfig_file}" ]]; then
  129. local local_modified="$(stat -c %Y "${kconfig_file}")"
  130. for config in "${KCONFIG_REL_PATHS[@]}"; do
  131. local kconfig_src="${config}"
  132. local src_modified="$(stat -c %Y "${kconfig_src}")"
  133. # Only update the config if it has been updated after the
  134. # previously cached config was created. This avoids
  135. # unnecessarily compiling the kernel and selftests.
  136. if [[ "${src_modified}" -gt "${local_modified}" ]]; then
  137. do_update_kconfig "$kernel_checkout" "$kconfig_file"
  138. # Once we have found one outdated configuration
  139. # there is no need to check other ones.
  140. break
  141. fi
  142. done
  143. else
  144. do_update_kconfig "$kernel_checkout" "$kconfig_file"
  145. fi
  146. }
  147. main()
  148. {
  149. local script_dir="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
  150. local kernel_checkout=$(realpath "${script_dir}"/../../../../)
  151. # By default the script searches for the kernel in the checkout directory but
  152. # it also obeys environment variables O= and KBUILD_OUTPUT=
  153. local kernel_bzimage="${kernel_checkout}/${BZIMAGE}"
  154. local command="${DEFAULT_COMMAND}"
  155. local update_b2c="no"
  156. local debug_shell="no"
  157. local build_only="no"
  158. while getopts ':hsud:j:b' opt; do
  159. case ${opt} in
  160. u)
  161. update_b2c="yes"
  162. ;;
  163. d)
  164. OUTPUT_DIR="$OPTARG"
  165. ;;
  166. j)
  167. NUM_COMPILE_JOBS="$OPTARG"
  168. ;;
  169. s)
  170. command="/bin/sh"
  171. debug_shell="yes"
  172. ;;
  173. b)
  174. build_only="yes"
  175. ;;
  176. h)
  177. usage
  178. exit 0
  179. ;;
  180. \? )
  181. echo "Invalid Option: -$OPTARG"
  182. usage
  183. exit 1
  184. ;;
  185. : )
  186. echo "Invalid Option: -$OPTARG requires an argument"
  187. usage
  188. exit 1
  189. ;;
  190. esac
  191. done
  192. shift $((OPTIND -1))
  193. # trap 'catch "$?"' EXIT
  194. if [[ "${build_only}" == "no" && "${debug_shell}" == "no" ]]; then
  195. if [[ $# -eq 0 ]]; then
  196. echo "No command specified, will run ${DEFAULT_COMMAND} in the vm"
  197. else
  198. command="$@"
  199. if [[ "${command}" == "/bin/bash" || "${command}" == "bash" ]]
  200. then
  201. debug_shell="yes"
  202. fi
  203. fi
  204. fi
  205. local kconfig_file="${OUTPUT_DIR}/latest.config"
  206. local make_command="make -j ${NUM_COMPILE_JOBS} KCONFIG_CONFIG=${kconfig_file}"
  207. # Figure out where the kernel is being built.
  208. # O takes precedence over KBUILD_OUTPUT.
  209. if [[ "${O:=""}" != "" ]]; then
  210. if is_rel_path "${O}"; then
  211. O="$(realpath "${PWD}/${O}")"
  212. fi
  213. kernel_bzimage="${O}/${BZIMAGE}"
  214. make_command="${make_command} O=${O}"
  215. elif [[ "${KBUILD_OUTPUT:=""}" != "" ]]; then
  216. if is_rel_path "${KBUILD_OUTPUT}"; then
  217. KBUILD_OUTPUT="$(realpath "${PWD}/${KBUILD_OUTPUT}")"
  218. fi
  219. kernel_bzimage="${KBUILD_OUTPUT}/${BZIMAGE}"
  220. make_command="${make_command} KBUILD_OUTPUT=${KBUILD_OUTPUT}"
  221. fi
  222. local b2c="${OUTPUT_DIR}/vm2c.py"
  223. echo "Output directory: ${OUTPUT_DIR}"
  224. mkdir -p "${OUTPUT_DIR}"
  225. update_kconfig "${kernel_checkout}" "${kconfig_file}"
  226. recompile_kernel "${kernel_checkout}" "${make_command}"
  227. update_selftests "${kernel_checkout}" "${make_command}"
  228. if [[ "${build_only}" == "no" ]]; then
  229. if [[ "${update_b2c}" == "no" && ! -f "${b2c}" ]]; then
  230. echo "vm2c script not found in ${b2c}"
  231. update_b2c="yes"
  232. fi
  233. if [[ "${update_b2c}" == "yes" ]]; then
  234. download $B2C_URL $b2c
  235. chmod +x $b2c
  236. fi
  237. run_vm "${kernel_checkout}" $b2c "${kernel_bzimage}" "${command}"
  238. if [[ "${debug_shell}" != "yes" ]]; then
  239. echo "Logs saved in ${OUTPUT_DIR}/${LOG_FILE}"
  240. fi
  241. exit $(cat ${OUTPUT_DIR}/${EXIT_STATUS_FILE})
  242. fi
  243. }
  244. main "$@"