github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/pkg/sentry/platform/cpuid_amd64.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  //go:build amd64
    16  // +build amd64
    17  
    18  package platform
    19  
    20  import (
    21  	"bytes"
    22  
    23  	"github.com/metacubex/gvisor/pkg/context"
    24  	"github.com/metacubex/gvisor/pkg/cpuid"
    25  	"github.com/metacubex/gvisor/pkg/hostarch"
    26  	"github.com/metacubex/gvisor/pkg/sentry/arch"
    27  	"github.com/metacubex/gvisor/pkg/usermem"
    28  )
    29  
    30  // taskWrapper wraps a context.Context.
    31  type taskWrapper struct {
    32  	context.Context
    33  }
    34  
    35  // emulationContext is used for emulation.
    36  //
    37  // It wraps an existing context but prioritizes resolution via context.NoTask,
    38  // since the task state should not be modified during emulation. However, we
    39  // allow logging and other operations to be directed to the correct task.
    40  type emulationContext struct {
    41  	taskWrapper
    42  	context.NoTask
    43  }
    44  
    45  // TryCPUIDEmulate checks for a CPUID instruction and performs emulation.
    46  func TryCPUIDEmulate(ctx context.Context, mm MemoryManager, ac *arch.Context64) bool {
    47  	s := ac.StateData()
    48  	inst := make([]byte, len(arch.CPUIDInstruction))
    49  	tasklessCtx := emulationContext{
    50  		taskWrapper: taskWrapper{ctx},
    51  	}
    52  	if _, err := mm.CopyIn(&tasklessCtx, hostarch.Addr(s.Regs.Rip), inst, usermem.IOOpts{
    53  		IgnorePermissions:  true,
    54  		AddressSpaceActive: true,
    55  	}); err != nil {
    56  		return false
    57  	}
    58  	if !bytes.Equal(inst, arch.CPUIDInstruction[:]) {
    59  		return false
    60  	}
    61  	fs := cpuid.FromContext(ctx)
    62  	out := fs.Function.Query(cpuid.In{
    63  		Eax: uint32(s.Regs.Rax),
    64  		Ecx: uint32(s.Regs.Rcx),
    65  	})
    66  	s.Regs.Rax = uint64(out.Eax)
    67  	s.Regs.Rbx = uint64(out.Ebx)
    68  	s.Regs.Rcx = uint64(out.Ecx)
    69  	s.Regs.Rdx = uint64(out.Edx)
    70  	s.Regs.Rip += uint64(len(inst))
    71  	return true
    72  }