github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/platform/kvm/context.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package kvm 16 17 import ( 18 "sync/atomic" 19 20 "github.com/SagerNet/gvisor/pkg/abi/linux" 21 pkgcontext "github.com/SagerNet/gvisor/pkg/context" 22 "github.com/SagerNet/gvisor/pkg/hostarch" 23 "github.com/SagerNet/gvisor/pkg/ring0" 24 "github.com/SagerNet/gvisor/pkg/sentry/arch" 25 "github.com/SagerNet/gvisor/pkg/sentry/platform" 26 "github.com/SagerNet/gvisor/pkg/sentry/platform/interrupt" 27 ) 28 29 // context is an implementation of the platform context. 30 // 31 // This is a thin wrapper around the machine. 32 type context struct { 33 // machine is the parent machine, and is immutable. 34 machine *machine 35 36 // info is the linux.SignalInfo cached for this context. 37 info linux.SignalInfo 38 39 // interrupt is the interrupt context. 40 interrupt interrupt.Forwarder 41 } 42 43 // Switch runs the provided context in the given address space. 44 func (c *context) Switch(ctx pkgcontext.Context, mm platform.MemoryManager, ac arch.Context, _ int32) (*linux.SignalInfo, hostarch.AccessType, error) { 45 as := mm.AddressSpace() 46 localAS := as.(*addressSpace) 47 48 // Grab a vCPU. 49 cpu := c.machine.Get() 50 51 // Enable interrupts (i.e. calls to vCPU.Notify). 52 if !c.interrupt.Enable(cpu) { 53 c.machine.Put(cpu) // Already preempted. 54 return nil, hostarch.NoAccess, platform.ErrContextInterrupt 55 } 56 57 // Set the active address space. 58 // 59 // This must be done prior to the call to Touch below. If the address 60 // space is invalidated between this line and the call below, we will 61 // flag on entry anyways. When the active address space below is 62 // cleared, it indicates that we don't need an explicit interrupt and 63 // that the flush can occur naturally on the next user entry. 64 cpu.active.set(localAS) 65 66 // Prepare switch options. 67 switchOpts := ring0.SwitchOpts{ 68 Registers: &ac.StateData().Regs, 69 FloatingPointState: ac.FloatingPointData(), 70 PageTables: localAS.pageTables, 71 Flush: localAS.Touch(cpu), 72 FullRestore: ac.FullRestore(), 73 } 74 75 // Take the blue pill. 76 at, err := cpu.SwitchToUser(switchOpts, &c.info) 77 78 // Clear the address space. 79 cpu.active.set(nil) 80 81 // Increment the number of user exits. 82 atomic.AddUint64(&cpu.userExits, 1) 83 84 // Release resources. 85 c.machine.Put(cpu) 86 87 // All done. 88 c.interrupt.Disable() 89 return &c.info, at, err 90 } 91 92 // Interrupt interrupts the running context. 93 func (c *context) Interrupt() { 94 c.interrupt.NotifyInterrupt() 95 } 96 97 // Release implements platform.Context.Release(). 98 func (c *context) Release() {} 99 100 // FullStateChanged implements platform.Context.FullStateChanged. 101 func (c *context) FullStateChanged() {} 102 103 // PullFullState implements platform.Context.PullFullState. 104 func (c *context) PullFullState(as platform.AddressSpace, ac arch.Context) {}