github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/pkg/sentry/devices/tpuproxy/vfio.go (about) 1 // Copyright 2024 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 tpuproxy 16 17 import ( 18 "fmt" 19 20 "golang.org/x/sys/unix" 21 "github.com/metacubex/gvisor/pkg/abi/linux" 22 "github.com/metacubex/gvisor/pkg/context" 23 "github.com/metacubex/gvisor/pkg/errors/linuxerr" 24 "github.com/metacubex/gvisor/pkg/fdnotifier" 25 "github.com/metacubex/gvisor/pkg/log" 26 "github.com/metacubex/gvisor/pkg/sentry/arch" 27 "github.com/metacubex/gvisor/pkg/sentry/kernel" 28 "github.com/metacubex/gvisor/pkg/sentry/vfs" 29 "github.com/metacubex/gvisor/pkg/usermem" 30 "github.com/metacubex/gvisor/pkg/waiter" 31 ) 32 33 // deviceFD implements vfs.FileDescriptionImpl for /dev/vfio/vfio. 34 type vfioFd struct { 35 vfsfd vfs.FileDescription 36 vfs.FileDescriptionDefaultImpl 37 vfs.DentryMetadataFileDescriptionImpl 38 vfs.NoLockFD 39 40 hostFd int32 41 device *vfioDevice 42 queue waiter.Queue 43 memmapFile vfioFDMemmapFile 44 } 45 46 // Release implements vfs.FileDescriptionImpl.Release. 47 func (fd *vfioFd) Release(context.Context) { 48 fdnotifier.RemoveFD(fd.hostFd) 49 fd.queue.Notify(waiter.EventHUp) 50 unix.Close(int(fd.hostFd)) 51 } 52 53 // EventRegister implements waiter.Waitable.EventRegister. 54 func (fd *vfioFd) EventRegister(e *waiter.Entry) error { 55 fd.queue.EventRegister(e) 56 if err := fdnotifier.UpdateFD(fd.hostFd); err != nil { 57 fd.queue.EventUnregister(e) 58 return err 59 } 60 return nil 61 } 62 63 // EventUnregister implements waiter.Waitable.EventUnregister. 64 func (fd *vfioFd) EventUnregister(e *waiter.Entry) { 65 fd.queue.EventUnregister(e) 66 if err := fdnotifier.UpdateFD(fd.hostFd); err != nil { 67 panic(fmt.Sprint("UpdateFD:", err)) 68 } 69 } 70 71 // Readiness implements waiter.Waitable.Readiness. 72 func (fd *vfioFd) Readiness(mask waiter.EventMask) waiter.EventMask { 73 return fdnotifier.NonBlockingPoll(fd.hostFd, mask) 74 } 75 76 // Epollable implements vfs.FileDescriptionImpl.Epollable. 77 func (fd *vfioFd) Epollable() bool { 78 return true 79 } 80 81 // Ioctl implements vfs.FileDescriptionImpl.Ioctl. 82 func (fd *vfioFd) Ioctl(ctx context.Context, uio usermem.IO, sysno uintptr, args arch.SyscallArguments) (uintptr, error) { 83 cmd := args[1].Uint() 84 t := kernel.TaskFromContext(ctx) 85 if t == nil { 86 panic("Ioctl should be called from a task context") 87 } 88 switch cmd { 89 case linux.VFIO_CHECK_EXTENSION: 90 return fd.checkExtension(extension(args[2].Int())) 91 case linux.VFIO_SET_IOMMU: 92 return fd.setIOMMU(extension(args[2].Int())) 93 } 94 return 0, linuxerr.ENOSYS 95 } 96 97 // checkExtension returns a positive integer when the given VFIO extension 98 // is supported, otherwise, it returns 0. 99 func (fd *vfioFd) checkExtension(ext extension) (uintptr, error) { 100 switch ext { 101 case linux.VFIO_TYPE1_IOMMU, linux.VFIO_SPAPR_TCE_IOMMU, linux.VFIO_TYPE1v2_IOMMU: 102 ret, err := ioctlInvoke[int32](fd.hostFd, linux.VFIO_CHECK_EXTENSION, int32(ext)) 103 if err != nil { 104 log.Warningf("check VFIO extension %s: %v", ext, err) 105 return 0, err 106 } 107 return ret, nil 108 } 109 return 0, linuxerr.EINVAL 110 } 111 112 // Set the iommu to the given type. The type must be supported by an iommu 113 // driver as verified by calling VFIO_CHECK_EXTENSION using the same type. 114 func (fd *vfioFd) setIOMMU(ext extension) (uintptr, error) { 115 switch ext { 116 case linux.VFIO_TYPE1_IOMMU, linux.VFIO_SPAPR_TCE_IOMMU, linux.VFIO_TYPE1v2_IOMMU: 117 ret, err := ioctlInvoke[int32](fd.hostFd, linux.VFIO_SET_IOMMU, int32(ext)) 118 if err != nil { 119 log.Warningf("set the IOMMU group to %s: %v", ext, err) 120 return 0, err 121 } 122 return ret, nil 123 } 124 return 0, linuxerr.EINVAL 125 } 126 127 // VFIO extension. 128 type extension int32 129 130 // String implements fmt.Stringer for VFIO extension string representation. 131 func (e extension) String() string { 132 switch e { 133 case linux.VFIO_TYPE1_IOMMU: 134 return "VFIO_TYPE1_IOMMU" 135 case linux.VFIO_SPAPR_TCE_IOMMU: 136 return "VFIO_SPAPR_TCE_IOMMU" 137 case linux.VFIO_TYPE1v2_IOMMU: 138 return "VFIO_TYPE1v2_IOMMU" 139 } 140 return "" 141 }