1# SPDX-License-Identifier: BSD-2-Clause 2# 3# Copyright (c) 2024 The FreeBSD Foundation 4# 5# This software was developed by Cybermancer Infosec <bofh@FreeBSD.org> 6# under sponsorship from the FreeBSD Foundation. 7# 8# Makefile for CI testing. 9# 10# User-driven targets: 11# ci: Run CI tests. Currently only smoke tests are supported. 12# ci-smokeit: Currently same as ci. 13# 14# Variables affecting the build process: 15# TARGET/TARGET_ARCH: architecture of built release (default: same as build host) 16# KERNELCONF: kernel configuration to use 17# USE_QEMU: Use QEMU for testing rather than bhyve 18# 19 20WORLDDIR?= ${.CURDIR}/../.. 21RELEASEDIR= ${WORLDDIR}/release 22MAKECONF?= /dev/null 23SRCCONF?= /dev/null 24_MEMORY!=sysctl -n hw.physmem 2>/dev/null 25PARALLEL_JOBS!=sysctl -n hw.ncpu 2>/dev/null || nproc 2>/dev/null 26TOTAL_MEMORY!=expr ${_MEMORY} / 1073741824 27KERNCONF?= GENERIC 28LOCALBASE?= /usr/local 29 30.if !defined(TARGET) || empty(TARGET) 31TARGET= ${MACHINE} 32.endif 33.if !defined(TARGET_ARCH) || empty(TARGET_ARCH) 34.if ${TARGET} == ${MACHINE} 35TARGET_ARCH= ${MACHINE_ARCH} 36.else 37TARGET_ARCH= ${TARGET} 38.endif 39.endif 40IMAKE= ${MAKE} TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} 41 42.if defined(CROSS_TOOLCHAIN) || !empty(CROSS_TOOLCHAIN) 43CROSS_TOOLCHAIN_PARAM= "CROSS_TOOLCHAIN=${CROSS_TOOLCHAIN}" 44.endif 45 46# Define OSRELEASE by using newvers.sh 47.if !defined(OSRELEASE) || empty(OSRELEASE) 48.for _V in TYPE BRANCH REVISION 49. if !defined(${_V}) || empty(${_V}) 50${_V}!= eval $$(awk '/^${_V}=/{print}' ${.CURDIR}/../../sys/conf/newvers.sh); echo $$${_V} 51. endif 52.endfor 53.for _V in ${TARGET_ARCH} 54.if !empty(TARGET:M${_V}) 55OSRELEASE= ${TYPE}-${REVISION}-${BRANCH}-${TARGET} 56VOLUME_LABEL= ${REVISION:C/[.-]/_/g}_${BRANCH:C/[.-]/_/g}_${TARGET} 57.else 58OSRELEASE= ${TYPE}-${REVISION}-${BRANCH}-${TARGET}-${TARGET_ARCH} 59VOLUME_LABEL= ${REVISION:C/[.-]/_/g}_${BRANCH:C/[.-]/_/g}_${TARGET_ARCH} 60.endif 61.endfor 62.endif 63 64.if exists(${.CURDIR}/tools/ci.conf) && !defined(CICONF) 65CICONF?= ${.CURDIR}/tools/ci.conf 66.endif 67SWAPSIZE?= 1g 68VMFS?= ufs 69FORMAT= raw 70CIIMAGE= ci-${OSRELEASE}-${GITREV}-${KERNCONF}.${FORMAT} 71VMSIZE?= 6g 72CITYPE?= 73TEST_VM_NAME= ci-${OSRELEASE}-${GITREV}-${KERNCONF} 74.if ${TOTAL_MEMORY} >= 16 75VM_MEM!=expr ${TOTAL_MEMORY} / 2 76.elif ${TOTAL_MEMORY} >=4 77VM_MEM=${TOTAL_MEMORY} 78.else 79echo "Please increase the memory to at least 4GB" 80exit 0 81.endif 82VM_MEM_SIZE?=${VM_MEM}g 83TIMEOUT_MS?=5400000 84TIMEOUT=$$((${TIMEOUT_MS} / 1000)) 85TIMEOUT_EXPECT=$$((${TIMEOUT} - 60)) 86TIMEOUT_VM=$$((${TIMEOUT_EXPECT} - 120)) 87.if exists(${.CURDIR}/Makefile.${TARGET_ARCH}) 88. include "${.CURDIR}/Makefile.${TARGET_ARCH}" 89.endif 90.if ${TARGET_ARCH} != ${MACHINE_ARCH} 91.if ( ${TARGET_ARCH} != "i386" ) || ( ${MACHINE_ARCH} != "amd64" ) 92QEMUSTATIC=/usr/local/bin/qemu-${QEMU_ARCH}-static 93QEMUTGT=portinstall-qemu 94.endif 95.endif 96QEMUTGT?= 97QEMU_DEVICES?=-device virtio-blk,drive=hd0 98QEMU_EXTRA_PARAM?= 99QEMU_MACHINE?=virt 100QEMUBIN=/usr/local/bin/qemu-system-${QEMU_ARCH} 101.if ${PARALLEL_JOBS} >= ${QEMU_MAX_CPU_COUNT} 102QEMU_CPU_COUNT=${QEMU_MAX_CPU_COUNT} 103.else 104QEMU_CPU_COUNT=${PARALLEL_JOBS} 105.endif 106.if ${VM_MEM} >= ${QEMU_MAX_MEM_SIZE} 107VM_MEM_SIZE=${QEMU_MAX_MEM_SIZE}g 108.else 109VM_MEM_SIZE=${VM_MEM}g 110.endif 111KLDVMMISLOADED!=kldload -q -n vmm 2>/dev/null && echo "1" || echo "0" 112.if ${KLDVMMISLOADED} == "0" 113USE_QEMU?=1 114.endif 115KLDFILEMONISLOADED!=kldload -q -n filemon 2>/dev/null && echo "1" || echo "0" 116.if ${KLDFILEMONISLOADED} == "1" 117METAMODE?=-DWITH_META_MODE 118.endif 119 120CLEANFILES= ${CIIMAGE} ci.img 121CLEANDIRS= ci-buildimage 122 123portinstall: portinstall-pkg portinstall-qemu portinstall-expect portinstall-${TARGET_ARCH:tl} .PHONY 124 125portinstall-pkg: .PHONY 126.if !exists(/usr/local/sbin/pkg-static) 127 env ASSUME_ALWAYS_YES=yes pkg bootstrap 128.endif 129 130portinstall-qemu: portinstall-pkg .PHONY 131.if !exists(/usr/local/bin/qemu-${TARGET_ARCH}-static) 132 env ASSUME_ALWAYS_YES=yes pkg install emulators/qemu-user-static 133.endif 134.if !exists(/usr/local/bin/qemu-system-${QEMU_ARCH}) 135 env ASSUME_ALWAYS_YES=yes pkg install emulators/qemu@nox11 136.endif 137 138portinstall-expect: portinstall-pkg .PHONY 139.if !exists(/usr/local/bin/expect) 140 env ASSUME_ALWAYS_YES=yes pkg install lang/expect 141.endif 142 143beforeclean: .PHONY 144 chflags -R noschg . 145 146.include <bsd.obj.mk> 147clean: beforeclean .PHONY 148 149ci-buildworld: .PHONY 150 @echo "Building world for ${TARGET_ARCH}" 151 ${IMAKE} -j${PARALLEL_JOBS} -C ${WORLDDIR} ${METAMODE} \ 152 ${CROSS_TOOLCHAIN_PARAM} __MAKE_CONF=${MAKECONF} SRCCONF=${SRCCONF} \ 153 buildworld > ${.CURDIR}/_.${TARGET_ARCH}.${.TARGET} 2>&1 || \ 154 (echo "${.TARGET} failed, check _.${TARGET_ARCH}.${.TARGET} for details" ; false) 155 156 157ci-buildkernel: ci-buildworld-${TARGET_ARCH:tl} .PHONY 158 @echo "Building kenrel for ${TARGET_ARCH"}" 159 ${IMAKE} -j${PARALLEL_JOBS} -C ${WORLDDIR} ${METAMODE} \ 160 ${CROSS_TOOLCHAIN_PARAM} __MAKE_CONF=${MAKECONF} \ 161 SRCCONF=${SRCCONF} buildkernel > ${.CURDIR}/_.${TARGET_ARCH}.${.TARGET} 2>&1 || \ 162 (echo "${.TARGET} failed, check _.${TARGET_ARCH}.${.TARGET} for details" ; false) 163 164ci-buildimage: ${QEMUTGT} ci-buildkernel-${TARGET_ARCH:tl} .PHONY 165 @echo "Building ci image for ${TARGET_ARCH"}" 166 mkdir -p ${.OBJDIR}/${.TARGET} 167 env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} SWAPSIZE=${SWAPSIZE} \ 168 QEMUSTATIC=${QEMUSTATIC} CITYPE=${CITYPE} \ 169 ${RELEASEDIR}/scripts/mk-vmimage.sh \ 170 -C ${RELEASEDIR}/tools/vmimage.subr -d ${.OBJDIR}/${.TARGET} -F ${VMFS} \ 171 -i ${.OBJDIR}/ci.img -s ${VMSIZE} -f ${FORMAT} \ 172 -S ${WORLDDIR} -o ${.OBJDIR}/${CIIMAGE} -c ${CICONF} \ 173 > ${.CURDIR}/_.${TARGET_ARCH}.${.TARGET} 2>&1 || \ 174 (echo "${.TARGET} failed, check _.${TARGET_ARCH}.${.TARGET} for details" ; false) 175 touch ${.TARGET} 176 177ci-setsmokevar: .PHONY 178CITYPE=smoke 179 180ci-runtest: ci-buildimage-${TARGET_ARCH:tl} portinstall .PHONY 181.if ${MACHINE} == "amd64" && ( ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "i386" ) && ( !defined(USE_QEMU) || empty(USE_QEMU) ) 182 /usr/sbin/bhyvectl --vm=${TEST_VM_NAME} --destroy || true 183 /usr/sbin/bhyveload -c stdio -m ${VM_MEM_SIZE} -d ${CIIMAGE} ${TEST_VM_NAME} 184 expect -c "set timeout ${TIMEOUT_EXPECT}; \ 185 spawn /usr/bin/timeout -k 60 ${TIMEOUT_VM} /usr/sbin/bhyve \ 186 -c ${PARALLEL_JOBS} -m ${VM_MEM_SIZE} -A -H -P \ 187 -s 0:0,hostbridge \ 188 -s 1:0,lpc \ 189 -s 2:0,virtio-blk,${CIIMAGE} \ 190 -l com1,stdio \ 191 ${TEST_VM_NAME}; \ 192 expect { eof }" 193 /usr/sbin/bhyvectl --vm=${TEST_VM_NAME} --destroy 194.else 195 timeout -k 60 ${TIMEOUT_VM} ${QEMUBIN} \ 196 -machine ${QEMU_MACHINE} \ 197 -smp ${QEMU_CPU_COUNT} \ 198 -m ${VM_MEM_SIZE} \ 199 -nographic \ 200 -no-reboot \ 201 ${QEMU_EXTRA_PARAM} \ 202 -drive if=none,file=${CIIMAGE},format=raw,id=hd0 \ 203 ${QEMU_DEVICES} 204.endif 205 206ci-checktarget: .PHONY 207.if ${TARGET_ARCH} != "aarch64" && \ 208 ${TARGET_ARCH} != "amd64" && \ 209 ${TARGET_ARCH} != "armv7" && \ 210 ${TARGET_ARCH} != "powerpc64" && \ 211 ${TARGET_ARCH} != "powerpc64le" && \ 212 ${TARGET_ARCH} != "riscv64" 213 @false 214.ERROR: 215 @echo "Error: ${TARGET_ARCH} is not supported on ${TYPE} ${REVISION} ${BRANCH}" 216.endif 217 218ci-smokeit: ci-setsmokevar ci-checktarget .WAIT ci-runtest-${TARGET_ARCH:tl} .PHONY 219 220ci: ci-smokeit .PHONY 221 222.include "${RELEASEDIR}/Makefile.inc1" 223