diff --git a/pkg/limayaml/defaults.go b/pkg/limayaml/defaults.go index 1736b96fe33..383db3a202b 100644 --- a/pkg/limayaml/defaults.go +++ b/pkg/limayaml/defaults.go @@ -60,47 +60,6 @@ var ( currentUser = Must(user.Current()) ) -func defaultCPUType() CPUType { - // x86_64 + TCG + max was previously unstable until 2021. - // https://bugzilla.redhat.com/show_bug.cgi?id=1999700 - // https://bugs.launchpad.net/qemu/+bug/1748296 - defaultX8664 := "max" - if runtime.GOOS == "windows" && runtime.GOARCH == "amd64" { - // https://github.com/lima-vm/lima/pull/3487#issuecomment-2846253560 - // > #931 intentionally prevented the code from setting it to max when running on Windows, - // > and kept it at qemu64. - // - // TODO: remove this if "max" works with the latest qemu - defaultX8664 = "qemu64" - } - cpuType := map[Arch]string{ - AARCH64: "max", - ARMV7L: "max", - X8664: defaultX8664, - PPC64LE: "max", - RISCV64: "max", - S390X: "max", - } - for arch := range cpuType { - if IsNativeArch(arch) && IsAccelOS() { - if HasHostCPU() { - cpuType[arch] = "host" - } - } - if arch == X8664 && runtime.GOOS == "darwin" { - // disable AVX-512, since it requires trapping instruction faults in guest - // Enterprise Linux requires either v2 (SSE4) or v3 (AVX2), but not yet v4. - cpuType[arch] += ",-avx512vl" - - // Disable pdpe1gb on Intel Mac - // https://github.com/lima-vm/lima/issues/1485 - // https://stackoverflow.com/a/72863744/5167443 - cpuType[arch] += ",-pdpe1gb" - } - } - return cpuType -} - //go:embed containerd.yaml var defaultContainerdYAML []byte @@ -312,28 +271,25 @@ func FillDefault(y, d, o *LimaYAML, filePath string, warn bool) { } } - cpuType := defaultCPUType() - var overrideCPUType bool - for k, v := range d.CPUType { - if v != "" { - overrideCPUType = true - cpuType[k] = v - } + if y.VMOpts.QEMU.CPUType == nil { + y.VMOpts.QEMU.CPUType = CPUType{} } - for k, v := range y.CPUType { - if v != "" { - overrideCPUType = true - cpuType[k] = v + // TODO: This check should be removed when we completely eliminate `CPUType` from limayaml. + if len(y.CPUType) > 0 { + if warn { + logrus.Warn("The top-level `cpuType` field is deprecated and will be removed in a future release. Please migrate to `vmOpts.qemu.cpuType`.") } - } - for k, v := range o.CPUType { - if v != "" { - overrideCPUType = true - cpuType[k] = v + for arch, v := range y.CPUType { + if v == "" { + continue + } + if existing, ok := y.VMOpts.QEMU.CPUType[arch]; ok && existing != "" && existing != v { + logrus.Warnf("Conflicting cpuType for arch %q: top-level=%q, vmOpts.qemu=%q; using vmOpts.qemu value", arch, v, existing) + continue + } + y.VMOpts.QEMU.CPUType[arch] = v } - } - if *y.VMType == QEMU || overrideCPUType { - y.CPUType = cpuType + y.CPUType = nil } if y.CPUs == nil { diff --git a/pkg/limayaml/defaults_test.go b/pkg/limayaml/defaults_test.go index 6384270927d..5f02e1f32ad 100644 --- a/pkg/limayaml/defaults_test.go +++ b/pkg/limayaml/defaults_test.go @@ -78,7 +78,6 @@ func TestFillDefault(t *testing.T) { VMType: &defaultVMType, OS: ptr.Of(LINUX), Arch: ptr.Of(arch), - CPUType: defaultCPUType(), CPUs: ptr.Of(defaultCPUs()), Memory: ptr.Of(defaultMemoryAsString()), Disk: ptr.Of(defaultDiskSizeAsString()), @@ -338,14 +337,6 @@ func TestFillDefault(t *testing.T) { VMType: ptr.Of("vz"), OS: ptr.Of("unknown"), Arch: ptr.Of("unknown"), - CPUType: CPUType{ - AARCH64: "arm64", - ARMV7L: "armhf", - X8664: "amd64", - PPC64LE: "ppc64le", - RISCV64: "riscv64", - S390X: "s390x", - }, CPUs: ptr.Of(7), Memory: ptr.Of("5GiB"), Disk: ptr.Of("105GiB"), @@ -558,14 +549,6 @@ func TestFillDefault(t *testing.T) { VMType: ptr.Of("qemu"), OS: ptr.Of(LINUX), Arch: ptr.Of(arch), - CPUType: CPUType{ - AARCH64: "uber-arm", - ARMV7L: "armv8", - X8664: "pentium", - PPC64LE: "power10", - RISCV64: "sifive-u54", - S390X: "z14", - }, CPUs: ptr.Of(12), Memory: ptr.Of("7GiB"), Disk: ptr.Of("117GiB"), diff --git a/pkg/limayaml/limayaml.go b/pkg/limayaml/limayaml.go index d72e5b602c8..a21c4aa5cf0 100644 --- a/pkg/limayaml/limayaml.go +++ b/pkg/limayaml/limayaml.go @@ -10,13 +10,14 @@ import ( ) type LimaYAML struct { - Base BaseTemplates `yaml:"base,omitempty" json:"base,omitempty"` - MinimumLimaVersion *string `yaml:"minimumLimaVersion,omitempty" json:"minimumLimaVersion,omitempty" jsonschema:"nullable"` - VMType *VMType `yaml:"vmType,omitempty" json:"vmType,omitempty" jsonschema:"nullable"` - VMOpts VMOpts `yaml:"vmOpts,omitempty" json:"vmOpts,omitempty"` - OS *OS `yaml:"os,omitempty" json:"os,omitempty" jsonschema:"nullable"` - Arch *Arch `yaml:"arch,omitempty" json:"arch,omitempty" jsonschema:"nullable"` - Images []Image `yaml:"images,omitempty" json:"images,omitempty" jsonschema:"nullable"` + Base BaseTemplates `yaml:"base,omitempty" json:"base,omitempty"` + MinimumLimaVersion *string `yaml:"minimumLimaVersion,omitempty" json:"minimumLimaVersion,omitempty" jsonschema:"nullable"` + VMType *VMType `yaml:"vmType,omitempty" json:"vmType,omitempty" jsonschema:"nullable"` + VMOpts VMOpts `yaml:"vmOpts,omitempty" json:"vmOpts,omitempty"` + OS *OS `yaml:"os,omitempty" json:"os,omitempty" jsonschema:"nullable"` + Arch *Arch `yaml:"arch,omitempty" json:"arch,omitempty" jsonschema:"nullable"` + Images []Image `yaml:"images,omitempty" json:"images,omitempty" jsonschema:"nullable"` + // Deprecated: Use VMOpts.Qemu.CPUType instead. CPUType CPUType `yaml:"cpuType,omitempty" json:"cpuType,omitempty" jsonschema:"nullable"` CPUs *int `yaml:"cpus,omitempty" json:"cpus,omitempty" jsonschema:"nullable"` Memory *string `yaml:"memory,omitempty" json:"memory,omitempty" jsonschema:"nullable"` // go-units.RAMInBytes @@ -111,6 +112,7 @@ type VMOpts struct { type QEMUOpts struct { MinimumVersion *string `yaml:"minimumVersion,omitempty" json:"minimumVersion,omitempty" jsonschema:"nullable"` + CPUType CPUType `yaml:"cpuType,omitempty" json:"cpuType,omitempty" jsonschema:"nullable"` } type Rosetta struct { diff --git a/pkg/limayaml/validate.go b/pkg/limayaml/validate.go index 42c4faa5890..bf7d6ecd462 100644 --- a/pkg/limayaml/validate.go +++ b/pkg/limayaml/validate.go @@ -119,12 +119,6 @@ func Validate(y *LimaYAML, warn bool) error { } } - for arch := range y.CPUType { - if !slices.Contains(ArchTypes, arch) { - return fmt.Errorf("field `cpuType` uses unsupported arch %q", arch) - } - } - if *y.CPUs == 0 { return errors.New("field `cpus` must be set") } diff --git a/pkg/qemu/qemu.go b/pkg/qemu/qemu.go index 12e148bf3bc..43077d5fdee 100644 --- a/pkg/qemu/qemu.go +++ b/pkg/qemu/qemu.go @@ -16,6 +16,7 @@ import ( "path/filepath" "regexp" "runtime" + "slices" "strconv" "strings" "time" @@ -438,6 +439,67 @@ func audioDevice() string { return "oss" } +func defaultCPUType() limayaml.CPUType { + // x86_64 + TCG + max was previously unstable until 2021. + // https://bugzilla.redhat.com/show_bug.cgi?id=1999700 + // https://bugs.launchpad.net/qemu/+bug/1748296 + defaultX8664 := "max" + if runtime.GOOS == "windows" && runtime.GOARCH == "amd64" { + // https://github.com/lima-vm/lima/pull/3487#issuecomment-2846253560 + // > #931 intentionally prevented the code from setting it to max when running on Windows, + // > and kept it at qemu64. + // + // TODO: remove this if "max" works with the latest qemu + defaultX8664 = "qemu64" + } + cpuType := map[limayaml.Arch]string{ + limayaml.AARCH64: "max", + limayaml.ARMV7L: "max", + limayaml.X8664: defaultX8664, + limayaml.PPC64LE: "max", + limayaml.RISCV64: "max", + limayaml.S390X: "max", + } + for arch := range cpuType { + if limayaml.IsNativeArch(arch) && limayaml.IsAccelOS() { + if limayaml.HasHostCPU() { + cpuType[arch] = "host" + } + } + if arch == limayaml.X8664 && runtime.GOOS == "darwin" { + // disable AVX-512, since it requires trapping instruction faults in guest + // Enterprise Linux requires either v2 (SSE4) or v3 (AVX2), but not yet v4. + cpuType[arch] += ",-avx512vl" + + // Disable pdpe1gb on Intel Mac + // https://github.com/lima-vm/lima/issues/1485 + // https://stackoverflow.com/a/72863744/5167443 + cpuType[arch] += ",-pdpe1gb" + } + } + return cpuType +} + +func resolveCPUType(y *limayaml.LimaYAML) string { + cpuType := defaultCPUType() + var overrideCPUType bool + for k, v := range y.VMOpts.QEMU.CPUType { + if !slices.Contains(limayaml.ArchTypes, *y.Arch) { + logrus.Warnf("field `vmOpts.qemu.cpuType` uses unsupported arch %q", k) + continue + } + if v != "" { + overrideCPUType = true + cpuType[k] = v + } + } + if overrideCPUType { + y.VMOpts.QEMU.CPUType = cpuType + } + + return cpuType[*y.Arch] +} + func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err error) { y := cfg.LimaYAML exe, args, err = Exe(*y.Arch) @@ -488,7 +550,7 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er } // CPU - cpu := y.CPUType[*y.Arch] + cpu := resolveCPUType(y) if runtime.GOOS == "darwin" && runtime.GOARCH == "amd64" { switch { case strings.HasPrefix(cpu, "host"), strings.HasPrefix(cpu, "max"): diff --git a/pkg/store/instance.go b/pkg/store/instance.go index 2af8f814f93..e27df0634eb 100644 --- a/pkg/store/instance.go +++ b/pkg/store/instance.go @@ -95,7 +95,7 @@ func Inspect(instName string) (*Instance, error) { inst.Config = y inst.Arch = *y.Arch inst.VMType = *y.VMType - inst.CPUType = y.CPUType[*y.Arch] + inst.CPUType = y.VMOpts.QEMU.CPUType[*y.Arch] inst.SSHAddress = "127.0.0.1" inst.SSHLocalPort = *y.SSH.LocalPort // maybe 0 inst.SSHConfigFile = filepath.Join(instDir, filenames.SSHConfig) diff --git a/pkg/vz/vz_driver_darwin.go b/pkg/vz/vz_driver_darwin.go index c131e3c1b6a..3354c67a9a9 100644 --- a/pkg/vz/vz_driver_darwin.go +++ b/pkg/vz/vz_driver_darwin.go @@ -117,6 +117,7 @@ func (l *LimaVzDriver) Validate() error { return fmt.Errorf("unsupported arch: %q", *l.Instance.Config.Arch) } + // TODO: This check should be removed when we completely eliminate `CPUType` from limayaml. for k, v := range l.Instance.Config.CPUType { if v != "" { logrus.Warnf("vmType %s: ignoring cpuType[%q]: %q", *l.Instance.Config.VMType, k, v) diff --git a/templates/default.yaml b/templates/default.yaml index 3b86d2d6985..443c79bc0fa 100644 --- a/templates/default.yaml +++ b/templates/default.yaml @@ -324,20 +324,22 @@ vmOpts: # Will be ignored if the vmType is not "qemu" # 🟢 Builtin default: not set minimumVersion: null + # Specify desired QEMU CPU type for each arch. + # You can see what options are available for host emulation with: `qemu-system-$(arch) -cpu help`. + # Setting of instructions is supported like this: "qemu64,+ssse3". + # 🟢 Builtin default: hard-coded arch map with type (see the output of `limactl info | jq .defaultTemplate.cpuType`) + cpuType: + # aarch64: "max" # (or "host" when running on aarch64 host) + # armv7l: "max" # (or "host" when running on armv7l host) + # riscv64: "max" # (or "host" when running on riscv64 host) + # x86_64: "max" # (or "host" when running on x86_64 host; additional options are appended on Intel Mac) # OS: "Linux". # 🟢 Builtin default: "Linux" os: null -# Specify desired QEMU CPU type for each arch. -# You can see what options are available for host emulation with: `qemu-system-$(arch) -cpu help`. -# Setting of instructions is supported like this: "qemu64,+ssse3". -# 🟢 Builtin default: hard-coded arch map with type (see the output of `limactl info | jq .defaultTemplate.cpuType`) +# DEPRECATED: Use vmOpts.qemu.cpuType instead. See the vmOpts.qemu.cpuType section above for configuration. cpuType: -# aarch64: "max" # (or "host" when running on aarch64 host) -# armv7l: "max" # (or "host" when running on armv7l host) -# riscv64: "max" # (or "host" when running on riscv64 host) -# x86_64: "max" # (or "host" when running on x86_64 host; additional options are appended on Intel Mac) rosetta: # Enable Rosetta inside the VM; needs `vmType: vz`