diff --git a/.gitignore b/.gitignore index cf80a1bcb..628d9bba1 100644 --- a/.gitignore +++ b/.gitignore @@ -23,5 +23,3 @@ source.tar source.tar.tmp target wget-log -# Cloud Hypervisor firmware, supplied by the user (see mk/ch.mk) -CLOUDHV.fd diff --git a/mk/ch.mk b/mk/ch.mk index 14c00a349..f3938954d 100644 --- a/mk/ch.mk +++ b/mk/ch.mk @@ -5,10 +5,16 @@ # make ch net=tap # use the tap device $(CH_TAP) instead of passt # make ch net=no # no network device # make ch-shutdown # stop the VM, from another terminal +# make ch-fetch # only download Cloud Hypervisor and its firmware # # x86_64 only. The guest boots through the CLOUDHV.fd UEFI firmware -# (https://github.com/cloud-hypervisor/edk2/releases), taken from the repo -# root unless CH_FIRMWARE is set. The disks are virtio-blk. +# (https://github.com/cloud-hypervisor/edk2/releases). The disks are virtio-blk. +# +# Cloud Hypervisor (cloud-hypervisor-static, ch-remote-static) and the firmware +# are pinned below. They are downloaded on first use into +# build/cloud-hypervisor/$(ARCH) and checked against their sha256. Set CH, +# CH_REMOTE or CH_FIRMWARE to use other files, e.g. CH=cloud-hypervisor for +# the one in PATH. # # The serial console puts this terminal in raw mode, so Ctrl-C goes to Redox. # Redox cannot power off Cloud Hypervisor by itself yet: use make ch-shutdown. @@ -26,9 +32,35 @@ # scripts/ch-tap-setup.sh (firewalld only) creates it and makes the host # the guest's DHCP server and NAT gateway. -CH?=$(shell command -v cloud-hypervisor || command -v ch) -CH_REMOTE?=ch-remote -CH_FIRMWARE?=$(wildcard CLOUDHV.fd) +# Pinned releases. To update one, change its version and the sha256 of its +# assets, which GitHub shows next to each file on the release page. Every +# version is downloaded into its own directory. +CH_VERSION=v54.0 +CH_FIRMWARE_VERSION=ch-97eeb7b09 +CH_URL=https://github.com/cloud-hypervisor/cloud-hypervisor/releases/download/$(CH_VERSION) +CH_FIRMWARE_URL=https://github.com/cloud-hypervisor/edk2/releases/download/$(CH_FIRMWARE_VERSION) +CH_DIR=build/cloud-hypervisor/$(ARCH) + +# Release assets and their sha256, per ARCH +CH_ASSET_x86_64=cloud-hypervisor-static +CH_SHA256_x86_64=4f4f98a3d661a40f3e5272627cc895a1b2e525f2f6bedf5f895f9cd21ba5c65b +CH_REMOTE_ASSET_x86_64=ch-remote-static +CH_REMOTE_SHA256_x86_64=acd5be240d5c73373effbe818908fc03e313ec8486237904bff11d93b71b1c83 +CH_FIRMWARE_ASSET_x86_64=CLOUDHV.fd +CH_FIRMWARE_SHA256_x86_64=dc2fc8f0e43b96712d9fccc52a3a590769606412b3e1bc911d217addd3bef624 + +ifneq ($(CH_ASSET_$(ARCH)),) + CH_PINNED=$(CH_DIR)/$(CH_VERSION)/$(CH_ASSET_$(ARCH)) + CH_REMOTE_PINNED=$(CH_DIR)/$(CH_VERSION)/$(CH_REMOTE_ASSET_$(ARCH)) + CH_FIRMWARE_PINNED=$(CH_DIR)/edk2-$(CH_FIRMWARE_VERSION)/$(CH_FIRMWARE_ASSET_$(ARCH)) +endif + +CH?=$(CH_PINNED) +CH_REMOTE?=$(CH_REMOTE_PINNED) +CH_FIRMWARE?=$(CH_FIRMWARE_PINNED) +# Only the pinned files in use are downloaded. +CH_DOWNLOADS=$(filter $(CH_PINNED) $(CH_REMOTE_PINNED) $(CH_FIRMWARE_PINNED),$(CH) $(CH_REMOTE) $(CH_FIRMWARE)) + CH_SMP?=4 CH_MEM?=2048 CH_API_SOCK?=$(BUILD)/ch.sock @@ -71,15 +103,23 @@ ifneq ($(strip $(share)),) CHFLAGS+=$(foreach i,$(share_idx),--fs tag=$(call vfs_tag,$(i)),socket=$(call vfs_sock,$(i))) endif -.PHONY: ch ch-check ch-deps ch-shutdown +# $(1): CH, CH_REMOTE or CH_FIRMWARE. When it is set to something other than +# the pinned download, it must be an existing file or a command in PATH. +ch_check_set=$(if $(filter-out $($(1)_PINNED),$($(1))),$(if $(or $(wildcard $($(1))),$(shell command -v $($(1)))),,$(error $(1)=$($(1)) not found. Leave $(1) unset to use the pinned download))) + +.PHONY: ch ch-check ch-deps ch-fetch ch-shutdown ch-check: $(if $(filter x86_64,$(ARCH)),,$(error Cloud Hypervisor: only ARCH=x86_64 is supported)) - $(if $(CH),,$(error cloud-hypervisor not found. Get cloud-hypervisor-static from https://github.com/cloud-hypervisor/cloud-hypervisor/releases and put it in PATH or set CH=/path/to/cloud-hypervisor)) - $(if $(wildcard $(CH_FIRMWARE)),,$(error CLOUDHV.fd not found. Get it from https://github.com/cloud-hypervisor/edk2/releases and put it in the repo root or set CH_FIRMWARE=/path/to/CLOUDHV.fd)) + $(if $(filter $(HOST_ARCH),$(ARCH)),,$(error Cloud Hypervisor: ARCH=$(ARCH) cannot run on this $(HOST_ARCH) host)) + $(call ch_check_set,CH) + $(call ch_check_set,CH_REMOTE) + $(call ch_check_set,CH_FIRMWARE) $(if $(filter tap,$(net)),$(if $(ch_tap_found),,$(error no tap device $(CH_TAP). Create it with scripts/ch-tap-setup.sh or leave out net=tap to use passt))) -ch-deps: $(DISK) $(EXTRA_DISK) +ch-deps: $(DISK) $(EXTRA_DISK) $(CH_DOWNLOADS) + +ch-fetch: ch-check $(CH_DOWNLOADS) ch: ch-check ch-deps ifneq ($(wildcard $(MOUNT_DIR)),) @@ -94,7 +134,29 @@ endif rm -f "$(CH_API_SOCK)" $(VIRTIOFS_RUN) $(PASST_RUN) $(CH) $(CHFLAGS) -ch-shutdown: - $(if $(shell command -v $(CH_REMOTE)),,$(error ch-remote not found. Get ch-remote-static from https://github.com/cloud-hypervisor/cloud-hypervisor/releases and put it in PATH or set CH_REMOTE=/path/to/ch-remote)) +ch-shutdown: $(filter $(CH_REMOTE_PINNED),$(CH_REMOTE)) + $(call ch_check_set,CH_REMOTE) # shutdown alone would leave Cloud Hypervisor running. $(CH_REMOTE) --api-socket "$(CH_API_SOCK)" shutdown-vmm + +# Downloads $(1) to $@ if its sha256 is $(2), and sets mode $(3) if given. +# It goes through $@.partial, so $@ only ever holds a checked download. +define ch_download + mkdir -p "$(@D)" + curl -fL --retry 3 --retry-delay 1 -o "$@.partial" "$(1)" + echo "$(2) $@.partial" | sha256sum --check --quiet - \ + || { rm -f "$@.partial"; echo "ch: $(1) does not match the pinned sha256 $(2)" >&2; exit 1; } + $(if $(3),chmod $(3) "$@.partial") + mv "$@.partial" "$@" +endef + +ifneq ($(CH_PINNED),) +$(CH_PINNED): + $(call ch_download,$(CH_URL)/$(@F),$(CH_SHA256_$(ARCH)),+x) + +$(CH_REMOTE_PINNED): + $(call ch_download,$(CH_URL)/$(@F),$(CH_REMOTE_SHA256_$(ARCH)),+x) + +$(CH_FIRMWARE_PINNED): + $(call ch_download,$(CH_FIRMWARE_URL)/$(@F),$(CH_FIRMWARE_SHA256_$(ARCH))) +endif diff --git a/podman_bootstrap.sh b/podman_bootstrap.sh index 58d077423..ddaec0de9 100755 --- a/podman_bootstrap.sh +++ b/podman_bootstrap.sh @@ -498,6 +498,12 @@ virtiofsd_find() # Download a static x86_64 virtiofsd build from the upstream CI into # ~/.cache/virtiofsd-redox, after asking for confirmation. # Override the source with VIRTIOFSD_URL. +# +# TODO: this is the CI build of upstream's main branch, so it is neither +# pinned nor checked: virtiofsd releases do not ship binaries or checksums +# yet. Once they do, move this download into mk/virtiofs.mk, pinned to a +# release and checked against its sha256 like Cloud Hypervisor in mk/ch.mk, +# and pass it to scripts/virtiofs-run.sh through VIRTIOFSD. ############################################################################### virtiofsd_download() {