@ -1,6 +1,18 @@
#!/usr/bin/env bash
#!/usr/bin/env bash
export LC_ALL=C
export LC_ALL=C
function web_get() {
local URL="${1}"
local FILE=$(echo "${URL##*/}")
if [ ! -e "${VMDIR}/${FILE}" ]; then
wget -q -c "${URL}" -O "${VMDIR}/${FILE}"
if [ $? -ne 0 ]; then
echo "ERROR! Failed to download ${URL}"
exit 1
fi
fi
}
function disk_delete() {
function disk_delete() {
if [ -e "${disk_img}" ]; then
if [ -e "${disk_img}" ]; then
rm "${disk_img}"
rm "${disk_img}"
@ -113,8 +125,7 @@ enable_usb_passthrough() {
USB_DEV=$(lsusb -d ${VENDOR_ID}:${PRODUCT_ID} | cut -d' ' -f4 | cut -d':' -f1)
USB_DEV=$(lsusb -d ${VENDOR_ID}:${PRODUCT_ID} | cut -d' ' -f4 | cut -d':' -f1)
USB_NAME=$(lsusb -d ${VENDOR_ID}:${PRODUCT_ID} | cut -d' ' -f7-)
USB_NAME=$(lsusb -d ${VENDOR_ID}:${PRODUCT_ID} | cut -d' ' -f7-)
echo " - ${USB_NAME}"
echo " - ${USB_NAME}"
USB_PASSTHROUGH="${USB_PASSTHROUGH} -usb -device usb-host,vendorid=0x${VENDOR_ID},productid=0x${PRODUCT_ID}"
USB_PASSTHROUGH="${USB_PASSTHROUGH} -device usb-host,vendorid=0x${VENDOR_ID},productid=0x${PRODUCT_ID},bus=usb.0"
if [ ! -w /dev/bus/usb/${USB_BUS}/${USB_DEV} ]; then
if [ ! -w /dev/bus/usb/${USB_BUS}/${USB_DEV} ]; then
local EXEC_SCRIPT=1
local EXEC_SCRIPT=1
echo "chown root:${USER} /dev/bus/usb/${USB_BUS}/${USB_DEV}" >> "${TEMP_SCRIPT}"
echo "chown root:${USER} /dev/bus/usb/${USB_BUS}/${USB_DEV}" >> "${TEMP_SCRIPT}"
@ -156,13 +167,27 @@ function vm_boot() {
# Force to lowercase.
# Force to lowercase.
boot=$(echo ${boot,,})
boot=$(echo ${boot,,})
# A;ways Boot macOS using EFI
if [ "${guest_os}" == "macos" ]; then
boot="efi"
fi
if [ "${boot}" == "efi" ] || [ "${boot}" == "uefi" ]; then
if [ "${boot}" == "efi" ] || [ "${boot}" == "uefi" ]; then
if [ -e "${VIRGIL_PATH}/usr/share/qemu/edk2-x86_64-code.fd" ] ; then
if [ -e "${VIRGIL_PATH}/usr/share/qemu/edk2-x86_64-code.fd" ] ; then
if [ "${guest_os}" == "macos" ]; then
web_get "https://github.com/foxlet/macOS-Simple-KVM/raw/master/ESP.qcow2"
web_get "https://github.com/foxlet/macOS-Simple-KVM/raw/master/firmware/OVMF_CODE.fd"
web_get "https://github.com/foxlet/macOS-Simple-KVM/raw/master/firmware/OVMF_VARS-1024x768.fd"
local EFI_CODE="${VMDIR}/OVMF_CODE.fd"
local EFI_VARS="${VMDIR}/OVMF_VARS-1024x768.fd"
else
local EFI_CODE="${VIRGIL_PATH}/usr/share/qemu/edk2-x86_64-code.fd"
local EFI_CODE="${VIRGIL_PATH}/usr/share/qemu/edk2-x86_64-code.fd"
local EFI_VARS="${VMDIR}/${VMNAME}-vars.fd"
local EFI_VARS="${VMDIR}/${VMNAME}-vars.fd"
if [ ! -e "${EFI_VARS}" ]; then
if [ ! -e "${EFI_VARS}" ]; then
cp "${VIRGIL_PATH}/usr/share/qemu/edk2-i386-vars.fd" "${EFI_VARS}"
cp "${VIRGIL_PATH}/usr/share/qemu/edk2-i386-vars.fd" "${EFI_VARS}"
fi
fi
fi
echo " - BOOT: EFI"
echo " - BOOT: EFI"
else
else
echo " - BOOT: Legacy BIOS"
echo " - BOOT: Legacy BIOS"
@ -179,6 +204,14 @@ function vm_boot() {
linux)
linux)
DISPLAY_DEVICE="virtio-vga"
DISPLAY_DEVICE="virtio-vga"
;;
;;
macos)
CPU="-cpu Penryn,vendor=GenuineIntel,kvm=on,+aes,+avx,+avx2,+bmi1,+bmi2,+fma,+invtsc,+movbe,+pcid,+smep,+sse3,+sse4.2,+xgetbv1,+xsave,+xsavec,+xsaveopt"
readonly ROT_OSK="bheuneqjbexolgurfrjbeqfthneqrqcyrnfrqbagfgrny(p)NccyrPbzchgreVap"
readonly OSK=$(echo ${ROT_OSK} | rot13)
GUEST_TWEAKS="-device isa-applesmc,osk=${OSK}"
DISPLAY_DEVICE="VGA"
VIRGL="off"
;;
windows)
windows)
CPU="${CPU},hv_time"
CPU="${CPU},hv_time"
GUEST_TWEAKS="-no-hpet"
GUEST_TWEAKS="-no-hpet"
@ -200,11 +233,11 @@ function vm_boot() {
echo "ERROR! Failed to create ${disk_img}"
echo "ERROR! Failed to create ${disk_img}"
exit 1
exit 1
fi
fi
if [ -z "${iso}" ]; then
if [ -z "${iso}" ] && [ -z "${img}" ] ; then
echo "ERROR! You haven't specified a .iso image to boot from."
echo "ERROR! You haven't specified a .iso or .img image to boot from."
exit 1
exit 1
fi
fi
echo " Just created, booting from ${iso}"
echo " Just created, booting from ${iso}${img} "
if [ $? -ne 0 ]; then
if [ $? -ne 0 ]; then
echo "ERROR! Failed to create ${disk_img} of ${disk}. Stopping here."
echo "ERROR! Failed to create ${disk_img} of ${disk}. Stopping here."
exit 1
exit 1
@ -218,15 +251,16 @@ function vm_boot() {
else
else
DISK_CURR_SIZE=$(stat -c%s "${disk_img}")
DISK_CURR_SIZE=$(stat -c%s "${disk_img}")
if [ ${DISK_CURR_SIZE} -le ${DISK_MIN_SIZE} ]; then
if [ ${DISK_CURR_SIZE} -le ${DISK_MIN_SIZE} ]; then
echo " Looks unused, booting from ${iso}"
echo " Looks unused, booting from ${iso}${img} "
if [ -z "${iso}" ]; then
if [ -z "${iso}" ] && [ -z "${img}" ] ; then
echo "ERROR! You haven't specified a .iso image to boot from."
echo "ERROR! You haven't specified a .iso or .img image to boot from."
exit 1
exit 1
fi
fi
else
else
# If there is a disk image, that appears to have an install
# If there is a disk image, that appears to have an install
# then do not boot from the iso
# then do not boot from the iso/img
iso=""
iso=""
img=""
fi
fi
fi
fi
fi
fi
@ -251,6 +285,7 @@ function vm_boot() {
elif [ ${CORES_HOST} -ge 4 ]; then
elif [ ${CORES_HOST} -ge 4 ]; then
CORES_VM="2"
CORES_VM="2"
fi
fi
local SMP="-smp ${CORES_VM},sockets=1,cores=${CORES_VM},threads=1"
echo " - CPU: ${CORES_VM} Core(s)"
echo " - CPU: ${CORES_VM} Core(s)"
local RAM_VM="2G"
local RAM_VM="2G"
@ -331,10 +366,55 @@ function vm_boot() {
# Boot the iso image
# Boot the iso image
if [ "${boot}" == "efi" ] || [ "${boot}" == "uefi" ]; then
if [ "${boot}" == "efi" ] || [ "${boot}" == "uefi" ]; then
if [ "${guest_os}" == "macos" ]; then
if [ -z "${img}" ]; then
${QEMU} \
${QEMU} \
-name ${VMNAME},process=${VMNAME} \
-name ${VMNAME},process=${VMNAME} \
-enable-kvm -machine q35 ${GUEST_TWEAKS} \
-enable-kvm -machine q35 ${GUEST_TWEAKS} \
${CPU} -smp ${CORES_VM} \
${CPU} ${SMP} \
-m ${RAM_VM} -device virtio-balloon \
-drive if=pflash,format=raw,readonly,file="${EFI_CODE}" \
-drive if=pflash,format=raw,file="${EFI_VARS}" \
-drive id=ESP,cache=directsync,aio=native,if=none,format=qcow2,file="${VMDIR}/ESP.qcow2" \
-device virtio-blk-pci,drive=ESP,scsi=off \
-drive id=SystemDisk,cache=directsync,aio=native,if=none,format=qcow2,file="${disk_img}" ${STATUS_QUO} \
-device virtio-blk-pci,drive=SystemDisk,scsi=off \
${VIDEO} -display ${OUTPUT},gl=${GL}${OUTPUT_EXTRA} \
-device usb-ehci,id=usb -device usb-kbd,bus=usb.0 -device usb-tablet,bus=usb.0 ${USB_PASSTHROUGH} \
-device vmxnet3,netdev=nic -netdev ${NET},id=nic \
-audiodev pa,id=pa,server=unix:${XDG_RUNTIME_DIR}/pulse/native,out.stream-name=${LAUNCHER}-${VMNAME},in.stream-name=${LAUNCHER}-${VMNAME} \
-device intel-hda -device hda-duplex,audiodev=pa,mixer=off \
-rtc base=localtime,clock=host \
-serial mon:stdio \
"${@}"
else
${QEMU} \
-name ${VMNAME},process=${VMNAME} \
-enable-kvm -machine q35 ${GUEST_TWEAKS} \
${CPU} ${SMP} \
-m ${RAM_VM} -device virtio-balloon \
-drive if=pflash,format=raw,readonly,file="${EFI_CODE}" \
-drive if=pflash,format=raw,file="${EFI_VARS}" \
-drive id=ESP,cache=directsync,aio=native,if=none,format=qcow2,file="${VMDIR}/ESP.qcow2" \
-device virtio-blk-pci,drive=ESP,scsi=off \
-drive id=InstallMedia,cache=directsync,aio=native,if=none,format=raw,readonly,file="${img}" \
-device virtio-blk-pci,drive=InstallMedia,scsi=off \
-drive id=SystemDisk,cache=directsync,aio=native,if=none,format=qcow2,file="${disk_img}" ${STATUS_QUO} \
-device virtio-blk-pci,drive=SystemDisk,scsi=off \
${VIDEO} -display ${OUTPUT},gl=${GL}${OUTPUT_EXTRA} \
-device usb-ehci,id=usb -device usb-kbd,bus=usb.0 -device usb-tablet,bus=usb.0 ${USB_PASSTHROUGH} \
-device vmxnet3,netdev=nic -netdev ${NET},id=nic \
-audiodev pa,id=pa,server=unix:${XDG_RUNTIME_DIR}/pulse/native,out.stream-name=${LAUNCHER}-${VMNAME},in.stream-name=${LAUNCHER}-${VMNAME} \
-device intel-hda -device hda-duplex,audiodev=pa,mixer=off \
-rtc base=localtime,clock=host \
-serial mon:stdio \
"${@}"
fi
else
${QEMU} \
-name ${VMNAME},process=${VMNAME} \
-enable-kvm -machine q35 ${GUEST_TWEAKS} \
${CPU} ${SMP} \
-m ${RAM_VM} -device virtio-balloon \
-m ${RAM_VM} -device virtio-balloon \
-drive if=pflash,format=raw,readonly,file="${EFI_CODE}" \
-drive if=pflash,format=raw,readonly,file="${EFI_CODE}" \
-drive if=pflash,format=raw,file="${EFI_VARS}" \
-drive if=pflash,format=raw,file="${EFI_VARS}" \
@ -343,7 +423,7 @@ function vm_boot() {
-drive if=none,id=drive0,cache=directsync,aio=native,format=qcow2,file="${disk_img}" \
-drive if=none,id=drive0,cache=directsync,aio=native,format=qcow2,file="${disk_img}" \
-device virtio-blk-pci,drive=drive0,scsi=off ${STATUS_QUO} \
-device virtio-blk-pci,drive=drive0,scsi=off ${STATUS_QUO} \
${VIDEO} -display ${OUTPUT},gl=${GL}${OUTPUT_EXTRA} \
${VIDEO} -display ${OUTPUT},gl=${GL}${OUTPUT_EXTRA} \
-device qemu-xhci,id=xhci,p2=8,p3=8 -device usb-kbd,bus=xhci.0 -device usb-tablet,bus=xhci .0 ${USB_PASSTHROUGH} \
-device qemu-xhci,id=usb,p2=8,p3=8 -device usb-kbd,bus=usb.0 -device usb-tablet,bus=usb .0 ${USB_PASSTHROUGH} \
-device virtio-net,netdev=nic -netdev ${NET},id=nic \
-device virtio-net,netdev=nic -netdev ${NET},id=nic \
-audiodev pa,id=pa,server=unix:${XDG_RUNTIME_DIR}/pulse/native,out.stream-name=${LAUNCHER}-${VMNAME},in.stream-name=${LAUNCHER}-${VMNAME} \
-audiodev pa,id=pa,server=unix:${XDG_RUNTIME_DIR}/pulse/native,out.stream-name=${LAUNCHER}-${VMNAME},in.stream-name=${LAUNCHER}-${VMNAME} \
-device intel-hda -device hda-duplex,audiodev=pa,mixer=off \
-device intel-hda -device hda-duplex,audiodev=pa,mixer=off \
@ -356,18 +436,19 @@ function vm_boot() {
-chardev spicevmc,id=spicechannel0,name=vdagent \
-chardev spicevmc,id=spicechannel0,name=vdagent \
-serial mon:stdio \
-serial mon:stdio \
"${@}"
"${@}"
fi
else
else
${QEMU} \
${QEMU} \
-name ${VMNAME},process=${VMNAME} \
-name ${VMNAME},process=${VMNAME} \
-enable-kvm -machine q35 ${GUEST_TWEAKS} \
-enable-kvm -machine q35 ${GUEST_TWEAKS} \
${CPU} -smp ${CORE S_V M} \
${CPU} ${SMP } \
-m ${RAM_VM} -device virtio-balloon \
-m ${RAM_VM} -device virtio-balloon \
-drive media=cdrom,index=0,file="${iso}" \
-drive media=cdrom,index=0,file="${iso}" \
-drive media=cdrom,index=1,file="${driver_iso}" \
-drive media=cdrom,index=1,file="${driver_iso}" \
-drive if=none,id=drive0,cache=directsync,aio=native,format=qcow2,file="${disk_img}" \
-drive if=none,id=drive0,cache=directsync,aio=native,format=qcow2,file="${disk_img}" \
-device virtio-blk-pci,drive=drive0,scsi=off ${STATUS_QUO} \
-device virtio-blk-pci,drive=drive0,scsi=off ${STATUS_QUO} \
${VIDEO} -display ${OUTPUT},gl=${GL}${OUTPUT_EXTRA} \
${VIDEO} -display ${OUTPUT},gl=${GL}${OUTPUT_EXTRA} \
-device qemu-xhci,id=xhci,p2=8,p3=8 -device usb-kbd,bus=xhci.0 -device usb-tablet,bus=xhci .0 ${USB_PASSTHROUGH} \
-device qemu-xhci,id=usb,p2=8,p3=8 -device usb-kbd,bus=usb.0 -device usb-tablet,bus=usb .0 ${USB_PASSTHROUGH} \
-device virtio-net,netdev=nic -netdev ${NET},id=nic \
-device virtio-net,netdev=nic -netdev ${NET},id=nic \
-audiodev pa,id=pa,server=unix:${XDG_RUNTIME_DIR}/pulse/native,out.stream-name=${LAUNCHER}-${VMNAME},in.stream-name=${LAUNCHER}-${VMNAME} \
-audiodev pa,id=pa,server=unix:${XDG_RUNTIME_DIR}/pulse/native,out.stream-name=${LAUNCHER}-${VMNAME},in.stream-name=${LAUNCHER}-${VMNAME} \
-device intel-hda -device hda-duplex,audiodev=pa,mixer=off \
-device intel-hda -device hda-duplex,audiodev=pa,mixer=off \
@ -418,6 +499,7 @@ function usage() {
# Lowercase variables are used in the VM config file only
# Lowercase variables are used in the VM config file only
boot="legacy"
boot="legacy"
guest_os="linux"
guest_os="linux"
img=""
iso=""
iso=""
driver_iso=""
driver_iso=""
disk_img=""
disk_img=""