diff options
-rw-r--r-- | pkg/sentry/platform/kvm/machine_amd64.go | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/pkg/sentry/platform/kvm/machine_amd64.go b/pkg/sentry/platform/kvm/machine_amd64.go index 8f2c82e73..3af96c7e5 100644 --- a/pkg/sentry/platform/kvm/machine_amd64.go +++ b/pkg/sentry/platform/kvm/machine_amd64.go @@ -294,6 +294,28 @@ func (c *vCPU) fault(signal int32, info *arch.SignalInfo) (usermem.AccessType, e return accessType, platform.ErrContextSignal } +//go:nosplit +//go:noinline +func loadByte(ptr *byte) byte { + return *ptr +} + +// prefaultFloatingPointState touches each page of the floating point state to +// be sure that its physical pages are mapped. +// +// Otherwise the kernel can trigger KVM_EXIT_MMIO and an instruction that +// triggered a fault will be emulated by the kvm kernel code, but it can't +// emulate instructions like xsave and xrstor. +// +//go:nosplit +func prefaultFloatingPointState(data *fpu.State) { + size := len(*data) + for i := 0; i < size; i += usermem.PageSize { + loadByte(&(*data)[i]) + } + loadByte(&(*data)[size-1]) +} + // SwitchToUser unpacks architectural-details. func (c *vCPU) SwitchToUser(switchOpts ring0.SwitchOpts, info *arch.SignalInfo) (usermem.AccessType, error) { // Check for canonical addresses. @@ -324,6 +346,7 @@ func (c *vCPU) SwitchToUser(switchOpts ring0.SwitchOpts, info *arch.SignalInfo) // allocations occur. entersyscall() bluepill(c) + prefaultFloatingPointState(switchOpts.FloatingPointState) vector = c.CPU.SwitchToUser(switchOpts) exitsyscall() |