@@ -439,9 +439,20 @@ get_codename() { #get debian/ubuntu codename
439439 fi
440440}
441441
442+ package_installed () { # exit 0 if $1 package is installed, otherwise exit 1
443+ # from pi-apps
444+ local package=" $1 "
445+ [ -z " $package " ] && error " package_installed(): no package specified!"
446+ # find the package listed in /var/lib/dpkg/status
447+ # package_info "$package"
448+
449+ # directly search /var/lib/dpkg/status
450+ grep -x " Package: $package " /var/lib/dpkg/status -A 2 | grep -qxF ' Status: install ok installed'
451+ }
452+
442453install_dependencies () { # try to install everything BVM needs
443- required_commands=" git jq wget mkisofs qemu-img qemu-system-aarch64 remmina nmap wget yad uuidgen wiminfo"
444- apt_packages=" git jq wget genisoimage qemu-utils qemu-system-arm qemu-system-gui qemu-efi-aarch64 remmina remmina-plugin-rdp nmap wget yad uuid-runtime seabios ipxe-qemu wimtools"
454+ required_commands=" git jq wget mkisofs qemu-img qemu-system-aarch64 remmina nmap wget yad uuidgen wiminfo socat "
455+ apt_packages=" git jq wget genisoimage qemu-utils qemu-system-arm qemu-system-gui qemu-efi-aarch64 remmina remmina-plugin-rdp nmap wget yad uuid-runtime seabios ipxe-qemu wimtools socat "
445456
446457 # using freerdp version 2 instead of 3 because it does not freeze on login and has more reliable clipboard sync
447458 if [ " $XDG_SESSION_TYPE " == wayland ]; then
@@ -487,7 +498,15 @@ install_dependencies() { #try to install everything BVM needs
487498 if [ " $installneeded " == 1 ] && command -v apt > /dev/null; then
488499 status " Installing dependencies, please wait..."
489500 # don't change the flags here in this apt command without updating the apt-detecting code on the pi-apps install script for BVM
490- sudo apt install -y $apt_packages || error " APT failed to install required dependencies"
501+ IFS=' '
502+ will_install=' '
503+ for package in $apt_packages ; do
504+ if ! package_installed " $package " ; then
505+ will_install+=" $package "
506+ fi
507+ done
508+
509+ sudo apt install -y $will_install || error " APT failed to install required dependencies"
491510
492511 # upgrade qemu to version from bookworm-backports
493512 if [ " $( get_codename) " == bookworm ]; then
634653[ -z " $download_language " ] && download_language=" English (United States)"
635654[ -z " $debloat " ] && debloat=true
636655[ -z " $disksize " ] && disksize=40
656+ [ -z " $free_ram_goal " ] && free_ram_goal=100
637657if [ -z " $vm_mem " ]; then
638658 # choose RAM to allocate to VM - 1GB less than total RAM
639659 vm_mem=" $(( $(awk '/ MemTotal/ {print $2 }' / proc/ meminfo)/ 1024 / 1024 )) "
640- # edge case for 2GB Pies: allocate 2GB and hope for the best (2GB is the minimum it seems)
641- [ " $vm_mem " == 1 ] && vm_mem=2
642- [ " $mode " == firstboot ] && [ " $vm_mem " -gt 4 ] && vm_mem=4 # more than 4GB has no benefit for firstinstall
660+ # Force 2GB on <=2GB devices
661+ [ " $vm_mem " -le 1 ] && vm_mem=2
662+ # Take off 1GB on >=5GB devices
663+ [ " $vm_mem " -ge 4 ] && vm_mem=$(( vm_mem- 1 ))
664+ # so for boot mode, RAM allocation works out like this:
665+ # Pi VM
666+ # 1GB -> 2GB (likely fails)
667+ # 2GB -> 2GB
668+ # 4GB -> 3GB
669+ # 8GB -> 6GB
670+ # 16GB -> 14GB
671+
672+ # more than 4GB has no benefit for firstinstall
673+ [ " $mode " == firstboot ] && [ " $vm_mem " -gt 4 ] && vm_mem=4
643674fi
644675
645676debug " DIRECTORY: $DIRECTORY
646677mode: $mode
647678vmdir: $vmdir
648679vm_username: $vm_username
649680vm_password: $vm_password
681+ vm_mem: $vm_mem
650682rdp_port: $rdp_port
651683download_language: $download_language "
652684
@@ -1117,7 +1149,7 @@ To get a fresh VM up and running, use a sequence like this:
11171149
11181150 # forward guest's port 3389 to localhost port of our choice (handled by config file now)
11191151 # network_flags=(-netdev user,id=nic,hostfwd=tcp:127.0.0.1:${rdp_port}-:3389 -device virtio-net-pci,netdev=nic)
1120-
1152+ rm -f " $vmdir /qemu.pid "
11211153 # all QEMU flags are combined together here
11221154 full_qemu_flags=(-M virt,accel=kvm -cpu host -m ${vm_mem} G -smp $num_cores \
11231155 -name BVM,process=bvm \
@@ -1128,6 +1160,7 @@ To get a fresh VM up and running, use a sequence like this:
11281160 -device qemu-xhci \
11291161 -device usb-kbd \
11301162 -device usb-tablet \
1163+ -monitor unix:" $vmdir /qemu.sock" ,server,nowait \
11311164 " ${usb_forwarding_flags[@]} " \
11321165 " ${audio_flags[@]} " \
11331166 -rtc base=localtime,clock=host,driftfix=none \
@@ -1138,14 +1171,43 @@ To get a fresh VM up and running, use a sequence like this:
11381171
11391172 debug " full_qemu_flags: " " ${full_qemu_flags[@]} "
11401173
1174+ # always try to pick optimal VM RAM limit by sending repeated balloon requests
1175+ total_ram=$( grep MemTotal /proc/meminfo | awk ' {print int($2/1024)}' )
1176+
1177+ # try to keep free_ram_goal MB free RAM on Linux at all times by setting the balloon size of the VM
1178+ # Windows will eat as much RAM as possible for caches, so it can be reallocated as needed.
1179+ # This "balloon_popper" process is what's needed to make the virtio-balloon driver actually do something.
1180+ while true ; do
1181+ sleep 1
1182+ qemu_pid=" $( cat " $vmdir /qemu.pid" ) "
1183+ [ -z " $qemu_pid " ] && continue
1184+
1185+ free_ram=$( grep MemFree /proc/meminfo | awk ' {print int($2/1024)}' )
1186+ qemu_used_ram=$( grep VmRSS /proc/$qemu_pid /status | awk ' {print $2/1024}' | sed ' s/\..*//g' )
1187+ other_tasks_ram=$(( total_ram - (qemu_used_ram + free_ram)) )
1188+ # echo "other taks use $other_tasks_ram"
1189+ balloon_size=$(( total_ram - other_tasks_ram - free_ram_goal))
1190+ # echo "qemu using $qemu_used_ram, free $free_ram, balloon_size: $balloon_size"
1191+
1192+ echo " balloon $balloon_size " | socat - UNIX-CONNECT:" $vmdir /qemu.sock" & > /dev/null
1193+ done &
1194+ balloon_popper=$!
1195+
11411196 # run qemu with these flags
11421197 if [ " $use_taskset " == false ]; then
1143- qemu-system-aarch64 " ${full_qemu_flags[@]} " || error " QEMU did not exit successfully. "
1198+ qemu-system-aarch64 " ${full_qemu_flags[@]} "
11441199 else
11451200 # For rockchip (untested but based on https://gist.github.com/Vogtinator/293c4f90c5e92838f7e72610725905fd?permalink_comment_id=5378278#gistcomment-5378278)
1146- taskset -c " $( echo " $a76_cores " | tr ' \n' ' ,' | sed ' s/,$//g' ) " qemu-system-aarch64 " ${full_qemu_flags[@]} " || error " QEMU did not exit successfully."
1201+ taskset -c " $( echo " $a76_cores " | tr ' \n' ' ,' | sed ' s/,$//g' ) " qemu-system-aarch64 " ${full_qemu_flags[@]} "
1202+ fi
1203+ qemu_exit_code=$?
1204+ kill $balloon_popper
1205+
1206+ if [ $qemu_exit_code == 0 ]; then
1207+ status " QEMU closed."
1208+ else
1209+ error " QEMU did not exit successfully."
11471210 fi
1148- status " QEMU closed."
11491211 ;;
11501212 connect* )
11511213 # make sure the qemu process is running
0 commit comments