github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/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 "github.com/nicocha30/gvisor-ligolo/pkg/abi/linux" 19 pkgcontext "github.com/nicocha30/gvisor-ligolo/pkg/context" 20 "github.com/nicocha30/gvisor-ligolo/pkg/hostarch" 21 "github.com/nicocha30/gvisor-ligolo/pkg/ring0" 22 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/arch" 23 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/platform" 24 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/platform/interrupt" 25 ) 26 27 // context is an implementation of the platform context. 28 // 29 // This is a thin wrapper around the machine. 30 type context struct { 31 // machine is the parent machine, and is immutable. 32 machine *machine 33 34 // info is the linux.SignalInfo cached for this context. 35 info linux.SignalInfo 36 37 // interrupt is the interrupt context. 38 interrupt interrupt.Forwarder 39 } 40 41 // tryCPUIDError indicates that CPUID emulation should occur. 42 type tryCPUIDError struct{} 43 44 // Error implements error.Error. 45 func (tryCPUIDError) Error() string { return "cpuid emulation failed" } 46 47 // Switch runs the provided context in the given address space. 48 func (c *context) Switch(ctx pkgcontext.Context, mm platform.MemoryManager, ac *arch.Context64, _ int32) (*linux.SignalInfo, hostarch.AccessType, error) { 49 as := mm.AddressSpace() 50 localAS := as.(*addressSpace) 51 52 restart: 53 // Grab a vCPU. 54 cpu := c.machine.Get() 55 56 // Enable interrupts (i.e. calls to vCPU.Notify). 57 if !c.interrupt.Enable(cpu) { 58 c.machine.Put(cpu) // Already preempted. 59 return nil, hostarch.NoAccess, platform.ErrContextInterrupt 60 } 61 62 // Set the active address space. 63 // 64 // This must be done prior to the call to Touch below. If the address 65 // space is invalidated between this line and the call below, we will 66 // flag on entry anyways. When the active address space below is 67 // cleared, it indicates that we don't need an explicit interrupt and 68 // that the flush can occur naturally on the next user entry. 69 cpu.active.set(localAS) 70 71 // Prepare switch options. 72 switchOpts := ring0.SwitchOpts{ 73 Registers: &ac.StateData().Regs, 74 FloatingPointState: ac.FloatingPointData(), 75 PageTables: localAS.pageTables, 76 Flush: localAS.Touch(cpu), 77 FullRestore: ac.FullRestore(), 78 } 79 80 // Take the blue pill. 81 at, err := cpu.SwitchToUser(switchOpts, &c.info) 82 83 // Clear the address space. 84 cpu.active.set(nil) 85 86 // Increment the number of user exits. 87 cpu.userExits.Add(1) 88 userExitCounter.Increment() 89 90 // Release resources. 91 c.machine.Put(cpu) 92 93 // All done. 94 c.interrupt.Disable() 95 96 if err != nil { 97 if _, ok := err.(tryCPUIDError); ok { 98 // Does emulation work for the CPUID? 99 // 100 // We have to put the current vCPU, because 101 // TryCPUIDEmulate needs to read a user memory and it 102 // has to lock mm.activeMu for that, but it can race 103 // with as.invalidate that bonce all vcpu-s to gr0 and 104 // is called under mm.activeMu too. 105 if platform.TryCPUIDEmulate(ctx, mm, ac) { 106 goto restart 107 } 108 // If not a valid CPUID, then the signal should be 109 // delivered as is and the information is filled. 110 err = platform.ErrContextSignal 111 } 112 } 113 return &c.info, at, err 114 } 115 116 // Interrupt interrupts the running context. 117 func (c *context) Interrupt() { 118 c.interrupt.NotifyInterrupt() 119 } 120 121 // Release implements platform.Context.Release(). 122 func (c *context) Release() {} 123 124 // FullStateChanged implements platform.Context.FullStateChanged. 125 func (c *context) FullStateChanged() {} 126 127 // PullFullState implements platform.Context.PullFullState. 128 func (c *context) PullFullState(as platform.AddressSpace, ac *arch.Context64) error { return nil } 129 130 // PrepareSleep implements platform.Context.platform.Context. 131 func (*context) PrepareSleep() {}