diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 850e362aeff..3b394f7ac8e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,7 +25,8 @@ jobs: steps: - uses: actions/checkout@v4 with: - fetch-depth: 1 + # To avoid "failed to load YAML file \"templates/experimental/riscv64.yaml\": can't parse builtin Lima version \"3f3a6f6\": 3f3a6f6 is not in dotted-tri format" + fetch-depth: 0 - uses: actions/setup-go@v5 with: go-version: 1.23.x @@ -158,7 +159,8 @@ jobs: steps: - uses: actions/checkout@v4 with: - fetch-depth: 1 + # To avoid "failed to load YAML file \"templates/experimental/riscv64.yaml\": can't parse builtin Lima version \"3f3a6f6\": 3f3a6f6 is not in dotted-tri format" + fetch-depth: 0 - uses: actions/setup-go@v5 with: go-version: 1.23.x diff --git a/examples/experimental/riscv64.yaml b/examples/experimental/riscv64.yaml index 9da1e89d006..97861379cc1 100644 --- a/examples/experimental/riscv64.yaml +++ b/examples/experimental/riscv64.yaml @@ -1,22 +1,18 @@ -# This template requires Lima v0.11.0 or later. +# Lima v0.x users should use https://raw.githubusercontent.com/lima-vm/lima/v0.23.2/examples/experimental/riscv64.yaml +minimumLimaVersion: "1.0.0" +vmOpts: + qemu: + minimumVersion: "9.1.0" arch: "riscv64" images: - location: "https://cloud-images.ubuntu.com/releases/24.04/release-20240821/ubuntu-24.04-server-cloudimg-riscv64.img" arch: "riscv64" digest: "sha256:f5886ad4e405e689585dfef0e96c31b06478e0cb12bc7f3fae965759a32d729e" - kernel: - # Extracted from http://http.us.debian.org/debian/pool/main/u/u-boot/u-boot-qemu_2023.07+dfsg-1_all.deb (GPL-2.0) - location: "https://github.com/lima-vm/u-boot-qemu-mirror/releases/download/2023.07%2Bdfsg-7/qemu-riscv64_smode_uboot.elf" - digest: "sha256:d4b3a10c3ef04219641802a586dca905e768805f5a5164fb68520887df54f33c" # Fallback to the latest release image. # Hint: run `limactl prune` to invalidate the cache - location: "https://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-riscv64.img" arch: "riscv64" - kernel: - # Extracted from http://http.us.debian.org/debian/pool/main/u/u-boot/u-boot-qemu_2023.07+dfsg-1_all.deb (GPL-2.0) - location: "https://github.com/lima-vm/u-boot-qemu-mirror/releases/download/2023.07%2Bdfsg-1/qemu-riscv64_smode_uboot.elf" - digest: "sha256:d4b3a10c3ef04219641802a586dca905e768805f5a5164fb68520887df54f33c" mounts: - location: "~" diff --git a/pkg/limayaml/validate.go b/pkg/limayaml/validate.go index f8113f8ae73..65a6d4bef16 100644 --- a/pkg/limayaml/validate.go +++ b/pkg/limayaml/validate.go @@ -101,8 +101,6 @@ func Validate(y *LimaYAML, warn bool) error { if f.Kernel.Arch != f.Arch { return fmt.Errorf("images[%d].kernel has unexpected architecture %q, must be %q", i, f.Kernel.Arch, f.Arch) } - } else if f.Arch == RISCV64 { - return errors.New("riscv64 needs the kernel (e.g., \"uboot.elf\") to be specified") } if f.Initrd != nil { if err := validateFileObject(*f.Initrd, fmt.Sprintf("images[%d].initrd", i)); err != nil { diff --git a/pkg/qemu/qemu.go b/pkg/qemu/qemu.go index 10ab28c5330..c4981c763c3 100644 --- a/pkg/qemu/qemu.go +++ b/pkg/qemu/qemu.go @@ -573,7 +573,12 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er } args = appendArgsIfNoConflict(args, "-machine", machine) case limayaml.RISCV64: - machine := "virt,accel=" + accel + // https://github.com/tianocore/edk2/blob/edk2-stable202408/OvmfPkg/RiscVVirt/README.md#test + // > Note: the `acpi=off` machine property is specified because Linux guest + // > support for ACPI (that is, the ACPI consumer side) is a work in progress. + // > Currently, `acpi=off` is recommended unless you are developing ACPI support + // > yourself. + machine := "virt,acpi=off,accel=" + accel args = appendArgsIfNoConflict(args, "-machine", machine) case limayaml.ARMV7L: machine := "virt,accel=" + accel @@ -613,7 +618,7 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er firmware = downloadedFirmware logrus.Infof("Using existing firmware (%q)", firmware) } - if firmware == "" && *y.Arch != limayaml.RISCV64 { + if firmware == "" { firmware, err = getFirmware(exe, *y.Arch) if err != nil { return "", nil, err @@ -1031,6 +1036,14 @@ func qemuArch(arch limayaml.Arch) string { return arch } +// qemuEdk2 returns the arch string used by `/usr/local/share/qemu/edk2-*-code.fd`. +func qemuEdk2Arch(arch limayaml.Arch) string { + if arch == limayaml.RISCV64 { + return "riscv" + } + return qemuArch(arch) +} + func Exe(arch limayaml.Arch) (exe string, args []string, err error) { exeBase := "qemu-system-" + qemuArch(arch) envK := "QEMU_SYSTEM_" + strings.ToUpper(qemuArch(arch)) @@ -1094,7 +1107,7 @@ func getQemuVersion(qemuExe string) (*semver.Version, error) { func getFirmware(qemuExe string, arch limayaml.Arch) (string, error) { switch arch { - case limayaml.X8664, limayaml.AARCH64, limayaml.ARMV7L: + case limayaml.X8664, limayaml.AARCH64, limayaml.ARMV7L, limayaml.RISCV64: default: return "", fmt.Errorf("unexpected architecture: %q", arch) } @@ -1108,7 +1121,7 @@ func getFirmware(qemuExe string, arch limayaml.Arch) (string, error) { localDir := filepath.Dir(binDir) // "/usr/local" userLocalDir := filepath.Join(currentUser.HomeDir, ".local") // "$HOME/.local" - relativePath := fmt.Sprintf("share/qemu/edk2-%s-code.fd", qemuArch(arch)) + relativePath := fmt.Sprintf("share/qemu/edk2-%s-code.fd", qemuEdk2Arch(arch)) candidates := []string{ filepath.Join(userLocalDir, relativePath), // XDG-like filepath.Join(localDir, relativePath), // macOS (homebrew) @@ -1135,6 +1148,8 @@ func getFirmware(qemuExe string, arch limayaml.Arch) (string, error) { // Debian package "qemu-efi-arm" // Fedora package "edk2-arm" candidates = append(candidates, "/usr/share/AAVMF/AAVMF32_CODE.fd") + case limayaml.RISCV64: + // NOP, as EDK2 for RISCV64 is not packaged yet in well-known distros. } logrus.Debugf("firmware candidates = %v", candidates) diff --git a/pkg/qemu/qemu_driver.go b/pkg/qemu/qemu_driver.go index 59ece73bab0..d0687a0b707 100644 --- a/pkg/qemu/qemu_driver.go +++ b/pkg/qemu/qemu_driver.go @@ -296,7 +296,8 @@ func (l *LimaQemuDriver) killVhosts() error { } func (l *LimaQemuDriver) shutdownQEMU(ctx context.Context, timeout time.Duration, qCmd *exec.Cmd, qWaitCh <-chan error) error { - logrus.Info("Shutting down QEMU with ACPI") + // "power button" refers to ACPI on the most archs, except RISC-V + logrus.Info("Shutting down QEMU with the power button") if usernetIndex := limayaml.FirstUsernetIndex(l.Instance.Config); usernetIndex != -1 { client := usernet.NewClientByName(l.Instance.Config.Networks[usernetIndex].Lima) err := client.UnExposeSSH(l.SSHLocalPort)