github.com/racerxdl/gonx@v0.0.0-20210103083128-c5afc43bcbd2/services/nv/nv.go (about) 1 package nv 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "github.com/racerxdl/gonx/nx/nxerrors" 7 "github.com/racerxdl/gonx/nx/nxtypes" 8 "github.com/racerxdl/gonx/services/ipc" 9 "github.com/racerxdl/gonx/services/sm" 10 "github.com/racerxdl/gonx/svc" 11 "unsafe" 12 ) 13 14 const nvDebug = false 15 const transferMemSize = 3 * 1024 * 1024 16 17 //go:align 4096 18 var gpuSharedBuffer [transferMemSize]byte 19 20 var nvObject ipc.Object 21 var transferMem = nxtypes.Handle(0) 22 var nvInitializations = 0 23 24 func Init() (err error) { 25 if nvDebug { 26 println("NV::Init()") 27 } 28 nvInitializations++ 29 30 if nvInitializations > 1 { 31 return nil 32 } 33 34 smInitialize := false 35 nvsInitialize := false 36 memInitialize := false 37 38 defer func() { 39 if err != nil { 40 println("got error: %s", err) 41 nvInitializations-- 42 // Only clean-up this if errored 43 if memInitialize { 44 svc.CloseHandle(transferMem) 45 } 46 47 if nvsInitialize { 48 _ = ipc.Close(&nvObject) 49 } 50 } 51 52 // Always de-init sm 53 if smInitialize { 54 sm.Finalize() 55 } 56 }() 57 58 err = sm.Init() 59 if err != nil { 60 return fmt.Errorf("error initializing sm: %s", err) 61 } 62 smInitialize = true 63 64 //err = sm.GetService(&nvObject, "nvdrv:a") 65 err = sm.GetService(&nvObject, "nvdrv") 66 if err != nil { 67 return fmt.Errorf("error getting \"nvdrv:a\": %s", err) 68 } 69 nvsInitialize = true 70 71 r := svc.CreateTransferMemory(&transferMem, uintptr(unsafe.Pointer(&gpuSharedBuffer[0])), transferMemSize, 0) 72 73 if r != nxtypes.ResultOK { 74 return fmt.Errorf("fail to create transfer memory: result code %d", r) 75 } 76 memInitialize = true 77 78 handles := []nxtypes.Handle{0xFFFF8001, transferMem} 79 80 rq := ipc.MakeDefaultRequest(3) 81 rq.SetRawDataFromUint32Slice([]uint32{transferMemSize}) 82 rq.CopyHandles = handles 83 84 rs := ipc.ResponseFmt{} 85 rs.RawData = make([]byte, 4) // one uint32 86 87 err = ipc.Send(nvObject, &rq, &rs) 88 89 if err != nil { 90 return fmt.Errorf("error sending ipc: %s", err) 91 } 92 93 response := []uint32{ 94 binary.LittleEndian.Uint32(rs.RawData[:4]), 95 } 96 97 if response[0] != 0 { 98 return fmt.Errorf("nvidia error: %d", response[0]) 99 } 100 101 return nil 102 } 103 104 func nvForceFinalize() { 105 if nvDebug { 106 println("NV::ForceFinalize()") 107 } 108 if transferMem != 0 { 109 svc.CloseHandle(transferMem) 110 } 111 _ = ipc.Close(&nvObject) 112 nvObject = ipc.Object{} 113 nvInitializations = 0 114 } 115 116 func Finalize() { 117 if nvDebug { 118 println("NV::Finalize()") 119 } 120 nvInitializations-- 121 if nvInitializations <= 0 { 122 nvForceFinalize() 123 } 124 } 125 126 func Open(path string) (int32, error) { 127 if nvDebug { 128 fmt.Printf("NV::Open(%s)\n", path) 129 } 130 if nvInitializations <= 0 { 131 return -1, nxerrors.NVNotInitialized 132 } 133 134 bytePath := []byte(path) 135 136 buff := ipc.Buffer{} 137 buff.Type = 0x5 138 buff.Size = uint64(len(bytePath)) 139 buff.Addr = uintptr(unsafe.Pointer(&bytePath[0])) 140 141 rq := ipc.MakeDefaultRequest(0) 142 rq.Buffers = append(rq.Buffers, &buff) 143 144 rs := ipc.ResponseFmt{} 145 rs.RawData = make([]byte, 2*4) // Two uint32 146 147 err := ipc.Send(nvObject, &rq, &rs) 148 if err != nil { 149 return -1, err 150 } 151 152 response := []uint32{ 153 binary.LittleEndian.Uint32(rs.RawData[:4]), 154 binary.LittleEndian.Uint32(rs.RawData[4:]), 155 } 156 157 if response[1] != 0 { 158 return int32(response[1]), fmt.Errorf("nvopen failed: %d", response[1]) 159 } 160 161 return int32(response[0]), nil 162 } 163 164 func Close(fd int32) error { 165 if nvDebug { 166 fmt.Printf("NV::Close(%d)\n", fd) 167 } 168 if nvInitializations <= 0 { 169 return nxerrors.NVNotInitialized 170 } 171 rq := ipc.MakeDefaultRequest(2) 172 rq.SetRawDataFromUint32Slice([]uint32{uint32(fd)}) 173 174 rs := ipc.ResponseFmt{} 175 rs.RawData = make([]byte, 4) // one uint32 176 177 err := ipc.Send(nvObject, &rq, &rs) 178 if err != nil { 179 return fmt.Errorf("error on nvClose: %s", err) 180 } 181 182 res := binary.LittleEndian.Uint32(rs.RawData) 183 184 if res != 0 { 185 return fmt.Errorf("error on nvClose: result code: %d", res) 186 } 187 188 return nil 189 } 190 191 func Ioctl(fd int32, rqid uint32, arg unsafe.Pointer, size uintptr) (uint32, error) { 192 if nvDebug { 193 fmt.Printf("NV::Ioctl(%d, %d, %p, %d)\n", fd, rqid, arg, size) 194 } 195 if nvInitializations <= 0 { 196 return 0xFFFFFFFF, nxerrors.NVNotInitialized 197 } 198 InB := ipc.Buffer{ 199 Addr: uintptr(arg), 200 Size: uint64(size), 201 Type: 0x21, 202 } 203 204 OutB := ipc.Buffer{ 205 Addr: uintptr(arg), 206 Size: uint64(size), 207 Type: 0x22, 208 } 209 210 rq := ipc.MakeDefaultRequest(1) 211 rq.Buffers = []*ipc.Buffer{&InB, &OutB} 212 rq.SetRawDataFromUint32Slice([]uint32{uint32(fd), rqid, 0, 0}) 213 214 rs := ipc.ResponseFmt{} 215 rs.RawData = []byte{0, 0, 0, 0} // One uint32 216 217 err := ipc.Send(nvObject, &rq, &rs) 218 if err != nil { 219 return 0, err 220 } 221 222 res := binary.LittleEndian.Uint32(rs.RawData) 223 return res, nil 224 }