Add windows vm to FreeBSD on laptop.
This commit is contained in:
parent
aec97a5df6
commit
077155f835
@ -77,7 +77,6 @@ jail_list:
|
||||
# - name: mumbledb
|
||||
# mount: /var/db/murmur
|
||||
bhyve_dataset: zmass/encrypted/vm
|
||||
bhyve_list: []
|
||||
bhyve_canmount: "on"
|
||||
bhyve_bemount: "on"
|
||||
wireguard_directory: homeserver
|
||||
|
@ -49,7 +49,7 @@ jail_list:
|
||||
conf:
|
||||
src: nat_dhcp
|
||||
bhyve_dataset: zroot/freebsd/current/vm
|
||||
bhyve_list: []
|
||||
bhyve_bemount: off
|
||||
# efi_dev: /dev/gpt/EFI
|
||||
efi_dev: /dev/diskid/DISK-SJB7N717610407Q0Hp1
|
||||
sway_conf_files:
|
||||
|
@ -10,7 +10,7 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
function cleanup {
|
||||
switch_to_main_screen
|
||||
}
|
||||
for sig in EXIT INT QUIT HUP TERM; do
|
||||
for sig in EXIT; do
|
||||
trap "set +e; cleanup; exit" "$sig"
|
||||
done
|
||||
|
||||
|
@ -1,2 +1 @@
|
||||
bhyve_mountpoint: "/vm"
|
||||
bhyve_list: []
|
||||
|
@ -47,7 +47,7 @@ function cleanup {
|
||||
done
|
||||
}
|
||||
vms=()
|
||||
for sig in EXIT INT QUIT HUP TERM; do
|
||||
for sig in EXIT; do
|
||||
trap "set +e; sleep 10; cleanup" "$sig"
|
||||
done
|
||||
|
||||
@ -154,6 +154,8 @@ function start_vm {
|
||||
-c $CPU_CORES \
|
||||
-m $MEMORY \
|
||||
-H \
|
||||
-P \
|
||||
-o 'rtc.use_localtime=false' \
|
||||
-s 0,hostbridge \
|
||||
-s "4,nvme,/dev/zvol/${zfs_path}/disk0" \
|
||||
-s 30,xhci,tablet \
|
||||
|
285
ansible/roles/framework_laptop/files/launch_windows.bash
Normal file
285
ansible/roles/framework_laptop/files/launch_windows.bash
Normal file
@ -0,0 +1,285 @@
|
||||
#!/usr/local/bin/bash
|
||||
#
|
||||
set -euo pipefail
|
||||
IFS=$'\n\t'
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
# Share a host directory to the guest via 9pfs.
|
||||
#
|
||||
# Inside the VM run:
|
||||
# mount -t virtfs -o trans=virtio sharename /some/vm/path
|
||||
# mount -t 9p -o cache=mmap -o msize=512000 sharename /mnt/9p
|
||||
# mount -t 9p -o trans=virtio,cache=mmap,msize=512000 sharename /path/to/mountpoint
|
||||
# bhyve_options="-s 28,virtio-9p,sharename=/"
|
||||
|
||||
# Enable Sound
|
||||
# bhyve_options="-s 16,hda,play=/dev/dsp,rec=/dev/dsp"
|
||||
|
||||
# Example usage:
|
||||
#
|
||||
# doas bhyve_netgraph_bridge create-disk zdata/vm/poudriere /vm/poudriere 10
|
||||
# doas bhyve_netgraph_bridge start poudriere zdata/vm/poudriere /vm/poudriere /vm/iso/FreeBSD-13.2-RELEASE-amd64-bootonly.iso
|
||||
# doas bhyve_netgraph_bridge start poudriere zdata/vm/poudriere /vm/poudriere
|
||||
|
||||
: ${VERBOSE:="NO"} # or YES
|
||||
: ${CPU_CORES:="1"}
|
||||
: ${MEMORY:="1G"}
|
||||
: ${NETWORK:="NAT"} # or RAW or BOTH
|
||||
: ${IP_RANGE:="10.215.1.1/24"} # Ignored for RAW networks
|
||||
: ${INTERFACE_NAME:="jail_nat"} # or the external interface like lagg0 for RAW networks
|
||||
: ${BRIDGE_NAME:="bridge_$INTERFACE_NAME"} # or bridge_raw for RAW networks
|
||||
: ${VNC_ENABLE:="NO"}
|
||||
: ${VNC_LISTEN:="127.0.0.1:5900"}
|
||||
: ${VNC_WIDTH:="1920"}
|
||||
: ${VNC_HEIGHT:="1080"}
|
||||
|
||||
if [ "$VERBOSE" = "YES" ]; then
|
||||
set -x
|
||||
fi
|
||||
|
||||
############## Setup #########################
|
||||
|
||||
function cleanup {
|
||||
for vm in "${vms[@]}"; do
|
||||
log "Destroying bhyve vm $vm"
|
||||
bhyvectl "--vm=$vm" --destroy
|
||||
log "Destroyed bhyve vm $vm"
|
||||
done
|
||||
}
|
||||
vms=()
|
||||
for sig in EXIT; do
|
||||
trap "set +e; sleep 10; cleanup" "$sig"
|
||||
done
|
||||
|
||||
function die {
|
||||
local status_code="$1"
|
||||
shift
|
||||
(>&2 echo "${@}")
|
||||
exit "$status_code"
|
||||
}
|
||||
|
||||
function log {
|
||||
(>&2 echo "${@}")
|
||||
}
|
||||
|
||||
############## Program #########################
|
||||
|
||||
function main {
|
||||
local cmd="$1"
|
||||
shift 1
|
||||
if [ "$cmd" = "create-disk" ]; then
|
||||
create_disk "${@}"
|
||||
elif [ "$cmd" = "start" ]; then
|
||||
start_vm "${@}"
|
||||
else
|
||||
die 1 "Unrecognized command $cmd"
|
||||
fi
|
||||
}
|
||||
|
||||
function create_disk {
|
||||
local zfs_path="$1"
|
||||
local mount_path="$2"
|
||||
local gigabytes="$3"
|
||||
zfs create -o "mountpoint=$mount_path" "$zfs_path"
|
||||
cp /usr/local/share/edk2-bhyve/BHYVE_UEFI_VARS.fd "${mount_path}/"
|
||||
tee "${mount_path}/settings" <<EOF
|
||||
CPU_CORES="$CPU_CORES"
|
||||
MEMORY="$MEMORY"
|
||||
NETWORK="$NETWORK"
|
||||
IP_RANGE="$IP_RANGE"
|
||||
BRIDGE_NAME="$BRIDGE_NAME"
|
||||
INTERFACE_NAME="$INTERFACE_NAME"
|
||||
EOF
|
||||
zfs create -s "-V${gigabytes}G" -o volmode=dev -o primarycache=metadata -o secondarycache=none -o volblocksize=64K "$zfs_path/disk0"
|
||||
}
|
||||
|
||||
function start_vm {
|
||||
local name="$1"
|
||||
local zfs_path="$2"
|
||||
local mount_path="$3"
|
||||
local mount_cd="${4:-}"
|
||||
|
||||
if [ -e "${mount_path}/settings" ]; then
|
||||
source "${mount_path}/settings"
|
||||
fi
|
||||
|
||||
local host_interface_name="$INTERFACE_NAME" # for raw, external interface
|
||||
local bridge_name="$BRIDGE_NAME"
|
||||
local ip_range="$IP_RANGE" # for raw this value does not matter
|
||||
|
||||
local mac_address
|
||||
mac_address=$(calculate_mac_address "$name")
|
||||
|
||||
local additional_args=()
|
||||
|
||||
if [ "$NETWORK" = "NAT" ]; then
|
||||
assert_bridge "$host_interface_name" "$bridge_name" "$ip_range"
|
||||
local bridge_link_name=$(detect_available_link "${bridge_name}")
|
||||
additional_args+=("-s" "2:0,e1000,netgraph,path=${bridge_name}:,peerhook=${bridge_link_name},mac=${mac_address}")
|
||||
elif [ "$NETWORK" = "RAW" ]; then
|
||||
assert_raw "$host_interface_name" "$bridge_name"
|
||||
local bridge_link_name=$(detect_available_link "${bridge_name}")
|
||||
additional_args+=("-s" "2:0,virtio-net,netgraph,path=${bridge_name}:,peerhook=${bridge_link_name},mac=${mac_address}")
|
||||
elif [ "$NETWORK" = "BOTH" ]; then
|
||||
assert_bridge "jail_nat" "$bridge_name" "$ip_range"
|
||||
assert_raw "$host_interface_name" "bridge_raw"
|
||||
local bridge_link_name=$(detect_available_link "${bridge_name}")
|
||||
local raw_bridge_link_name=$(detect_available_link "bridge_raw")
|
||||
local raw_mac_address=$(calculate_mac_address "${name}_raw")
|
||||
additional_args+=("-s" "2:0,virtio-net,netgraph,path=${bridge_name}:,peerhook=${bridge_link_name},mac=${mac_address}")
|
||||
additional_args+=("-s" "3:0,virtio-net,netgraph,path=bridge_raw:,peerhook=${raw_bridge_link_name},mac=${raw_mac_address}")
|
||||
elif [ "$NETWORK" = "NONE" ]; then
|
||||
(>&2 echo "Not using any network.")
|
||||
else
|
||||
die 1 "Unrecognized NETWORK type $NETWORK"
|
||||
fi
|
||||
|
||||
|
||||
# -H release the CPU when guest issues HLT instruction. Otherwise 100% of core will be consumed.
|
||||
# -s 3,ahci-cd,/vm/.iso/archlinux-2023.04.01-x86_64.iso \
|
||||
# -s 29,fbuf,tcp=0.0.0.0:5900,w=1920,h=1080,wait \
|
||||
# -s 29,fbuf,tcp=0.0.0.0:5900,w=1920,h=1080 \
|
||||
|
||||
# TODO: Look into using nmdm instead of stdio for serial console
|
||||
if [ -n "$mount_cd" ]; then
|
||||
additional_args+=("-s" "5,ahci-cd,$mount_cd")
|
||||
fi
|
||||
if [ "$VNC_ENABLE" = "YES" ]; then
|
||||
additional_args+=("-s" "29,fbuf,tcp=$VNC_LISTEN,w=$VNC_WIDTH,h=$VNC_HEIGHT,wait")
|
||||
fi
|
||||
vms+=("$name")
|
||||
# Removes CPU_CORES because windows must be a single CPU in bhyve
|
||||
# -c $CPU_CORES \
|
||||
# We need tpm
|
||||
# -l "tpm,passthru,/dev/tpm0" \
|
||||
# -S \
|
||||
while true; do
|
||||
set -x
|
||||
set +e
|
||||
bhyve \
|
||||
-D \
|
||||
-c sockets=1,cores=2,threads=2 \
|
||||
-m $MEMORY \
|
||||
-H \
|
||||
-w \
|
||||
-o 'rtc.use_localtime=false' \
|
||||
-s 0,hostbridge \
|
||||
-s "4,nvme,/dev/zvol/${zfs_path}/disk0" \
|
||||
-s 16,hda,play=/dev/dsp,rec=/dev/dsp \
|
||||
-s 30,xhci,tablet \
|
||||
-s 31,lpc -l com1,stdio \
|
||||
-l "bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd,${mount_path}/BHYVE_UEFI_VARS.fd" \
|
||||
-U '5a63bcd1-5cb4-4401-8a6f-d4042fb928a6' \
|
||||
"${additional_args[@]}" \
|
||||
"$name"
|
||||
local exit_code=$?
|
||||
set -e
|
||||
set +x
|
||||
if [ $exit_code -eq 0 ]; then
|
||||
echo "Rebooting."
|
||||
sleep 5
|
||||
elif [ $exit_code -eq 1 ]; then
|
||||
echo "Powered off."
|
||||
break
|
||||
elif [ $exit_code -eq 2 ]; then
|
||||
echo "Halted."
|
||||
break
|
||||
elif [ $exit_code -eq 3 ]; then
|
||||
echo "Triple fault."
|
||||
break
|
||||
elif [ $exit_code -eq 4 ]; then
|
||||
echo "Exited due to an error."
|
||||
break
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function detect_available_link {
|
||||
local bridge_name="$1"
|
||||
local linknum=1
|
||||
while true; do
|
||||
local link_name="link${linknum}"
|
||||
if ! ng_exists "${bridge_name}:${link_name}"; then
|
||||
echo "$link_name"
|
||||
return
|
||||
fi
|
||||
linknum=$((linknum + 1))
|
||||
if [ "$linknum" -gt 90 ]; then
|
||||
(>&2 echo "No available links on bridge $bridge_name")
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function assert_bridge {
|
||||
local host_interface_name="$1"
|
||||
local bridge_name="$2"
|
||||
local ip_range="$3"
|
||||
|
||||
if ! ng_exists "${bridge_name}:"; then
|
||||
ngctl -d -f - <<EOF
|
||||
mkpeer . eiface hook ether
|
||||
name .:hook $host_interface_name
|
||||
EOF
|
||||
ngctl -d -f - <<EOF
|
||||
mkpeer ${host_interface_name}: bridge ether link0
|
||||
name ${host_interface_name}:ether $bridge_name
|
||||
EOF
|
||||
ifconfig $(ngctl msg "${host_interface_name}:" getifname | grep Args | cut -d '"' -f 2) name "${host_interface_name}" "$ip_range" up
|
||||
fi
|
||||
}
|
||||
|
||||
function assert_raw {
|
||||
local extif="$1"
|
||||
local bridge_name="$2"
|
||||
|
||||
kldload -n ng_bridge ng_eiface ng_ether
|
||||
|
||||
if ! ng_exists "${bridge_name}:"; then
|
||||
ngctlcat <<EOF
|
||||
# Create a bridge.
|
||||
mkpeer $extif: bridge lower link0
|
||||
# Assign a name to the bridge.
|
||||
name $extif:lower ${bridge_name}
|
||||
# Since the host is also using $extif, we need to connect the upper hook also. Otherwise we will lose connectivity.
|
||||
connect $extif: ${bridge_name}: upper link1
|
||||
|
||||
# Enable promiscuous mode so the host ethernet adapter accepts packets for all addresses
|
||||
msg $extif: setpromisc 1
|
||||
|
||||
# Do not overwrite source address on packets
|
||||
msg $extif: setautosrc 0
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
|
||||
function ng_exists {
|
||||
ngctl status "${1}" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
function calculate_mac_address {
|
||||
local name="$1"
|
||||
local source
|
||||
source=$(md5 -r -s "$name" | awk '{print $1}')
|
||||
echo "06:${source:0:2}:${source:2:2}:${source:4:2}:${source:6:2}:${source:8:2}"
|
||||
}
|
||||
|
||||
function find_available_port {
|
||||
local start_port="$1"
|
||||
local port="$start_port"
|
||||
while true; do
|
||||
sockstat -P tcp -p 443
|
||||
port=$((port + 1))
|
||||
done
|
||||
}
|
||||
|
||||
function ngctlcat {
|
||||
if [ "$VERBOSE" = "YES" ]; then
|
||||
tee /dev/tty | ngctl -d -f -
|
||||
else
|
||||
ngctl -d -f -
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
main "${@}"
|
46
ansible/roles/framework_laptop/files/windows
Normal file
46
ansible/roles/framework_laptop/files/windows
Normal file
@ -0,0 +1,46 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# REQUIRE: LOGIN
|
||||
# PROVIDE: windows
|
||||
# KEYWORD: shutdown
|
||||
|
||||
. /etc/rc.subr
|
||||
name=windows
|
||||
rcvar=${name}_enable
|
||||
start_cmd="${name}_start"
|
||||
stop_cmd="${name}_stop"
|
||||
status_cmd="${name}_status"
|
||||
load_rc_config $name
|
||||
|
||||
tmux_name="windows"
|
||||
|
||||
windows_start() {
|
||||
/usr/local/bin/tmux new-session -d -s "$tmux_name" "/usr/bin/env VNC_ENABLE=YES VNC_LISTEN=0.0.0.0:5900 /usr/local/bin/bash /usr/local/bin/launch_windows start windows zroot/freebsd/current/vm/windows /vm/windows /vm/.iso/Win11_23H2_English_x64v2.iso"
|
||||
}
|
||||
|
||||
windows_status() {
|
||||
if /usr/local/bin/tmux has-session -t $tmux_name 2>/dev/null; then
|
||||
echo "$tmux_name is running."
|
||||
else
|
||||
echo "$tmux_name is not running."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
windows_stop() {
|
||||
/usr/local/bin/tmux has-session -t $tmux_name 2>/dev/null && (
|
||||
/usr/local/bin/tmux kill-session -t $tmux_name
|
||||
sleep 10
|
||||
bhyvectl --vm=windows --destroy
|
||||
# kill `cat /var/run/windows.pid`
|
||||
)
|
||||
windows_wait_for_end
|
||||
}
|
||||
|
||||
windows_wait_for_end() {
|
||||
while /usr/local/bin/tmux has-session -t $tmux_name 2>dev/null; do
|
||||
sleep 1
|
||||
done
|
||||
}
|
||||
|
||||
run_rc_command "$1"
|
3
ansible/roles/framework_laptop/meta/main.yaml
Normal file
3
ansible/roles/framework_laptop/meta/main.yaml
Normal file
@ -0,0 +1,3 @@
|
||||
dependencies:
|
||||
- role: bhyve
|
||||
when: 'os_flavor == "freebsd"'
|
@ -7,3 +7,24 @@
|
||||
group: wheel
|
||||
loop:
|
||||
- disable_wifi_powersave
|
||||
|
||||
- name: Install scripts
|
||||
copy:
|
||||
src: "files/{{ item.src }}"
|
||||
dest: "{{ item.dest }}"
|
||||
mode: 0755
|
||||
owner: root
|
||||
group: wheel
|
||||
loop:
|
||||
- src: launch_windows.bash
|
||||
dest: /usr/local/bin/launch_windows
|
||||
|
||||
- name: Install rc script
|
||||
copy:
|
||||
src: "files/{{ item.src }}"
|
||||
dest: "/usr/local/etc/rc.d/{{ item.dest|default(item.src) }}"
|
||||
owner: root
|
||||
group: wheel
|
||||
mode: 0755
|
||||
loop:
|
||||
- src: windows
|
||||
|
@ -65,3 +65,11 @@
|
||||
loop:
|
||||
- gpe10-boot.service
|
||||
- gpe10-sleep.service
|
||||
# install swtpm
|
||||
# install edk2-ovmf for /usr/share/ovmf/OVMF.fd
|
||||
# install qemu-system-x86
|
||||
|
||||
# doas qemu-system-x86_64 -cdrom /vm/.iso/Win11_23H2_English_x64v2.iso -cpu Skylake-Client-v3 -enable-kvm -m 8192 —device chardev,socket,id=chrtpm,path=/tmp/emulated_tpm/swtpm-sock -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0 -smp 2 -device intel-hda -device hda-duplex -usb -nic user,ipv6=off,model=rtl8139,mac=84:1b:77:c9:03:a6 -bios /usr/share/edk2/x64/OVMF.fd -drive file=/dev/zvol/zroot/freebsd/current/vm/windows/disk0,format=raw,media=disk,if=none,id=nvm -device nvme,drive=nvm,serial=foo,opt_io_size=4096,min_io_size=4096,logical_block_size=4096,physical_block_size=4096
|
||||
|
||||
# doas mkdir /tmp/emulated_tpm
|
||||
# doas swtpm socket --tpmstate dir=/tmp/emulated_tpm --ctrl type=unixio,path=/tmp/emulated_tpm/swtpm-sock --log level=20 --tpm2
|
||||
|
@ -6,6 +6,7 @@
|
||||
"subnet4": [
|
||||
{
|
||||
"subnet": "10.215.1.0/24",
|
||||
"id": 1,
|
||||
"pools": [ { "pool": "10.215.1.10-10.215.1.200" } ],
|
||||
"option-data": [
|
||||
{
|
||||
|
@ -13,7 +13,7 @@ function cleanup {
|
||||
done
|
||||
}
|
||||
pods=()
|
||||
for sig in EXIT INT QUIT HUP TERM; do
|
||||
for sig in EXIT; do
|
||||
trap "set +e; cleanup" "$sig"
|
||||
done
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user