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) {}