diff --git a/src/runtime/pkg/govmm/qemu/qemu.go b/src/runtime/pkg/govmm/qemu/qemu.go index 46e845f9e4..c0c692a800 100644 --- a/src/runtime/pkg/govmm/qemu/qemu.go +++ b/src/runtime/pkg/govmm/qemu/qemu.go @@ -141,9 +141,16 @@ const ( func isDimmSupported(config *Config) bool { switch runtime.GOARCH { case "amd64", "386", "ppc64le", "arm64": - if config != nil && config.Machine.Type == MachineTypeMicrovm { - // microvm does not support NUMA - return false + if config != nil { + if config.Machine.Type == MachineTypeMicrovm { + // microvm does not support NUMA + return false + } + if config.Knobs.MemFDPrivate { + // TDX guests rely on MemFD Private, which + // does not have NUMA support yet + return false + } } return true default: @@ -2628,6 +2635,9 @@ type Knobs struct { // MemPrealloc will allocate all the RAM upfront MemPrealloc bool + // Private Memory FD meant for private memory map/unmap. + MemFDPrivate bool + // FileBackedMem requires Memory.Size and Memory.Path of the VM to // be set. FileBackedMem bool @@ -2992,10 +3002,13 @@ func (config *Config) appendMemoryKnobs() { return } var objMemParam, numaMemParam string + dimmName := "dimm1" if config.Knobs.HugePages { objMemParam = "memory-backend-file,id=" + dimmName + ",size=" + config.Memory.Size + ",mem-path=/dev/hugepages" numaMemParam = "node,memdev=" + dimmName + } else if config.Knobs.MemFDPrivate { + objMemParam = "memory-backend-memfd-private,id=" + dimmName + ",size=" + config.Memory.Size } else if config.Knobs.FileBackedMem && config.Memory.Path != "" { objMemParam = "memory-backend-file,id=" + dimmName + ",size=" + config.Memory.Size + ",mem-path=" + config.Memory.Path numaMemParam = "node,memdev=" + dimmName diff --git a/src/runtime/pkg/govmm/qemu/qemu_test.go b/src/runtime/pkg/govmm/qemu/qemu_test.go index 34ca776dfc..f585714d0b 100644 --- a/src/runtime/pkg/govmm/qemu/qemu_test.go +++ b/src/runtime/pkg/govmm/qemu/qemu_test.go @@ -632,6 +632,29 @@ func TestAppendMemoryFileBackedMemPrealloc(t *testing.T) { testConfigAppend(conf, knobs, memString+" "+knobsString, t) } +func TestAppendMemoryBackedMemFdPrivate(t *testing.T) { + conf := &Config{ + Memory: Memory{ + Size: "1G", + Slots: 8, + }, + } + memString := "-m 1G,slots=8" + testConfigAppend(conf, conf.Memory, memString, t) + + knobs := Knobs{ + MemFDPrivate: true, + MemShared: false, + } + objMemString := "-object memory-backend-memfd-private,id=dimm1,size=1G" + memBackendString := "-machine memory-backend=dimm1" + + knobsString := objMemString + " " + knobsString += memBackendString + + testConfigAppend(conf, knobs, memString+" "+knobsString, t) +} + func TestNoRebootKnob(t *testing.T) { conf := &Config{} diff --git a/src/runtime/virtcontainers/qemu.go b/src/runtime/virtcontainers/qemu.go index b03b176b4a..f4de0d0d2a 100644 --- a/src/runtime/virtcontainers/qemu.go +++ b/src/runtime/virtcontainers/qemu.go @@ -604,6 +604,23 @@ func (q *qemu) CreateVM(ctx context.Context, id string, network Network, hypervi return err } + if q.config.ConfidentialGuest { + // At this point we're safe to just check for the protection field + // on the hypervisor specific code, as availableGuestProtection() + // has been called earlier and we know we have the value stored. + if q.arch.getProtection() == tdxProtection { + knobs.MemFDPrivate = true + + // In case Nydus or VirtioFS is used, which may become a reality + // in the future, whenever we get those hardened for TDX, those + // knobs below would be automatically set. Let's make sure we + // pre-emptively disable them, and with that we can avoid some + // headaches in the future. + knobs.FileBackedMem = false + knobs.MemShared = false + } + } + kernelPath, err := q.config.KernelAssetPath() if err != nil { return err diff --git a/src/runtime/virtcontainers/qemu_arch_base.go b/src/runtime/virtcontainers/qemu_arch_base.go index 0dc9f46cde..763ccbb445 100644 --- a/src/runtime/virtcontainers/qemu_arch_base.go +++ b/src/runtime/virtcontainers/qemu_arch_base.go @@ -71,6 +71,9 @@ type qemuArch interface { // memoryTopology returns the memory topology using the given amount of memoryMb and hostMemoryMb memoryTopology(memoryMb, hostMemoryMb uint64, slots uint8) govmmQemu.Memory + // protection returns platform protection + getProtection() guestProtection + // appendConsole appends a console to devices appendConsole(ctx context.Context, devices []govmmQemu.Device, path string) ([]govmmQemu.Device, error) @@ -280,6 +283,10 @@ func (q *qemuArchBase) machine() govmmQemu.Machine { return q.qemuMachine } +func (q *qemuArchBase) getProtection() guestProtection { + return q.protection +} + func (q *qemuArchBase) qemuPath() string { return q.qemuExePath }