1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 1999-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 
25 
26 //***************************** Module Header **********************************
27 //
28 // This code is linked into the resource manager proper.  It receives the
29 //    ioctl from the resource manager's customer, unbundles the args and
30 //    calls the correct resman routines.
31 //
32 //******************************************************************************
33 
34 #include <core/prelude.h>
35 #include <core/locks.h>
36 #include <nv.h>
37 #include <nv_escape.h>
38 #include <osapi.h>
39 #include <rmapi/exports.h>
40 #include <nv-unix-nvos-params-wrappers.h>
41 
42 #include <nvos.h>
43 #include <class/cl0000.h> // NV01_ROOT
44 #include <class/cl0001.h> // NV01_ROOT_NON_PRIV
45 #include <class/cl0005.h> // NV01_EVENT
46 #include <class/cl003e.h> // NV01_MEMORY_SYSTEM
47 #include <class/cl0071.h> // NV01_MEMORY_SYSTEM_OS_DESCRIPTOR
48 
49 #include "rmapi/client_resource.h"
50 #include "nvlog/nvlog.h"
51 #include <nv-ioctl-nvlog.h>
52 
53 #include <ctrl/ctrl00fd.h>
54 
55 #define NV_CTL_DEVICE_ONLY(nv)                 \
56 {                                              \
57     if (((nv)->flags & NV_FLAG_CONTROL) == 0)  \
58     {                                          \
59         rmStatus = NV_ERR_INVALID_ARGUMENT;    \
60         goto done;                             \
61     }                                          \
62 }
63 
64 #define NV_ACTUAL_DEVICE_ONLY(nv)              \
65 {                                              \
66     if (((nv)->flags & NV_FLAG_CONTROL) != 0)  \
67     {                                          \
68         rmStatus = NV_ERR_INVALID_ARGUMENT;    \
69         goto done;                             \
70     }                                          \
71 }
72 
73 static NvBool RmIsDeviceRefNeeded(NVOS54_PARAMETERS *pApi)
74 {
75     switch(pApi->cmd)
76     {
77         case NV00FD_CTRL_CMD_ATTACH_GPU:
78             return NV_TRUE;
79         default:
80             return NV_FALSE;
81     }
82 }
83 
84 static NV_STATUS RmGetDeviceFd(NVOS54_PARAMETERS *pApi, NvS32 *pFd)
85 {
86     RMAPI_PARAM_COPY paramCopy;
87     void *pKernelParams;
88     NvU32 paramSize;
89     NV_STATUS status;
90 
91     *pFd = -1;
92 
93     switch(pApi->cmd)
94     {
95         case NV00FD_CTRL_CMD_ATTACH_GPU:
96             paramSize = sizeof(NV00FD_CTRL_ATTACH_GPU_PARAMS);
97             break;
98         default:
99             return NV_ERR_INVALID_ARGUMENT;
100     }
101 
102     RMAPI_PARAM_COPY_INIT(paramCopy, pKernelParams, pApi->params, paramSize, 1);
103 
104     status = rmapiParamsAcquire(&paramCopy, NV_TRUE);
105     if (status != NV_OK)
106         return status;
107 
108     switch(pApi->cmd)
109     {
110         case NV00FD_CTRL_CMD_ATTACH_GPU:
111             *pFd = (NvS32)((NV00FD_CTRL_ATTACH_GPU_PARAMS *)pKernelParams)->devDescriptor;
112             break;
113         default:
114             NV_ASSERT(0);
115             break;
116     }
117 
118     NV_ASSERT(rmapiParamsRelease(&paramCopy) == NV_OK);
119 
120     return status;
121 }
122 
123 // Only return errors through pApi->status
124 static void RmCreateOsDescriptor(NVOS32_PARAMETERS *pApi, API_SECURITY_INFO secInfo)
125 {
126     NV_STATUS rmStatus;
127     NvBool writable;
128     NvU32 flags = 0;
129     NvU64 allocSize, pageCount, *pPteArray = NULL;
130     void *pDescriptor, *pPageArray = NULL;
131 
132     pDescriptor = NvP64_VALUE(pApi->data.AllocOsDesc.descriptor);
133     if (((NvUPtr)pDescriptor & ~os_page_mask) != 0)
134     {
135         rmStatus = NV_ERR_NOT_SUPPORTED;
136         goto done;
137     }
138 
139     // Check to prevent an NvU64 overflow
140     if ((pApi->data.AllocOsDesc.limit + 1) == 0)
141     {
142         rmStatus = NV_ERR_INVALID_LIMIT;
143         goto done;
144     }
145 
146     allocSize = (pApi->data.AllocOsDesc.limit + 1);
147     pageCount = (1 + ((allocSize - 1) / os_page_size));
148 
149     writable = FLD_TEST_DRF(OS32, _ATTR2, _PROTECTION_USER, _READ_WRITE, pApi->data.AllocOsDesc.attr2);
150 
151     flags = FLD_SET_DRF_NUM(_LOCK_USER_PAGES, _FLAGS, _WRITE, writable, flags);
152     rmStatus = os_lock_user_pages(pDescriptor, pageCount, &pPageArray, flags);
153     if (rmStatus == NV_OK)
154     {
155         pApi->data.AllocOsDesc.descriptor = (NvP64)(NvUPtr)pPageArray;
156         pApi->data.AllocOsDesc.descriptorType = NVOS32_DESCRIPTOR_TYPE_OS_PAGE_ARRAY;
157     }
158     else if (rmStatus == NV_ERR_INVALID_ADDRESS)
159     {
160         rmStatus = os_lookup_user_io_memory(pDescriptor, pageCount,
161                 &pPteArray, &pPageArray);
162         if (rmStatus == NV_OK)
163         {
164             if (pPageArray != NULL)
165             {
166                 pApi->data.AllocOsDesc.descriptor = (NvP64)(NvUPtr)pPageArray;
167                 pApi->data.AllocOsDesc.descriptorType = NVOS32_DESCRIPTOR_TYPE_OS_PAGE_ARRAY;
168             }
169             else if (pPteArray != NULL)
170             {
171                 pApi->data.AllocOsDesc.descriptor = (NvP64)(NvUPtr)pPteArray;
172                 pApi->data.AllocOsDesc.descriptorType = NVOS32_DESCRIPTOR_TYPE_OS_IO_MEMORY;
173             }
174             else
175             {
176                 NV_ASSERT_FAILED("unknown memory import type");
177                 rmStatus = NV_ERR_NOT_SUPPORTED;
178             }
179         }
180     }
181     if (rmStatus != NV_OK)
182         goto done;
183 
184     Nv04VidHeapControlWithSecInfo(pApi, secInfo);
185 
186     if (pApi->status != NV_OK)
187     {
188         switch (pApi->data.AllocOsDesc.descriptorType)
189         {
190             default:
191                 break;
192             case NVOS32_DESCRIPTOR_TYPE_OS_PAGE_ARRAY:
193                 os_unlock_user_pages(pageCount, pPageArray);
194                 break;
195         }
196     }
197 
198 done:
199     if (rmStatus != NV_OK)
200         pApi->status = rmStatus;
201 }
202 
203 // Only return errors through pApi->status
204 static void RmAllocOsDescriptor(NVOS02_PARAMETERS *pApi, API_SECURITY_INFO secInfo)
205 {
206     NV_STATUS rmStatus = NV_OK;
207     NvU32 flags, attr, attr2;
208     NVOS32_PARAMETERS *pVidHeapParams;
209 
210     if (!FLD_TEST_DRF(OS02, _FLAGS, _LOCATION, _PCI, pApi->flags) ||
211         !FLD_TEST_DRF(OS02, _FLAGS, _MAPPING, _NO_MAP, pApi->flags))
212     {
213         rmStatus = NV_ERR_INVALID_FLAGS;
214         goto done;
215     }
216 
217     attr = DRF_DEF(OS32, _ATTR, _LOCATION, _PCI);
218 
219     if (FLD_TEST_DRF(OS02, _FLAGS, _COHERENCY, _CACHED, pApi->flags) ||
220         FLD_TEST_DRF(OS02, _FLAGS, _COHERENCY, _WRITE_BACK, pApi->flags))
221     {
222         attr = FLD_SET_DRF(OS32, _ATTR, _COHERENCY, _WRITE_BACK, attr);
223     }
224     else if (FLD_TEST_DRF(OS02, _FLAGS, _COHERENCY, _UNCACHED, pApi->flags))
225         attr = FLD_SET_DRF(OS32, _ATTR, _COHERENCY, _UNCACHED, attr);
226     else {
227         rmStatus = NV_ERR_INVALID_FLAGS;
228         goto done;
229     }
230 
231     if (FLD_TEST_DRF(OS02, _FLAGS, _PHYSICALITY, _CONTIGUOUS, pApi->flags))
232         attr = FLD_SET_DRF(OS32, _ATTR, _PHYSICALITY, _CONTIGUOUS, attr);
233     else
234         attr = FLD_SET_DRF(OS32, _ATTR, _PHYSICALITY, _NONCONTIGUOUS, attr);
235 
236     if (FLD_TEST_DRF(OS02, _FLAGS, _GPU_CACHEABLE, _YES, pApi->flags))
237         attr2 = DRF_DEF(OS32, _ATTR2, _GPU_CACHEABLE, _YES);
238     else
239         attr2 = DRF_DEF(OS32, _ATTR2, _GPU_CACHEABLE, _NO);
240 
241     pVidHeapParams = portMemAllocNonPaged(sizeof(NVOS32_PARAMETERS));
242     if (pVidHeapParams == NULL)
243     {
244         rmStatus = NV_ERR_NO_MEMORY;
245         goto done;
246     }
247     portMemSet(pVidHeapParams, 0, sizeof(NVOS32_PARAMETERS));
248 
249     pVidHeapParams->hRoot = pApi->hRoot;
250     pVidHeapParams->hObjectParent = pApi->hObjectParent;
251     pVidHeapParams->function = NVOS32_FUNCTION_ALLOC_OS_DESCRIPTOR;
252 
253     flags = (NVOS32_ALLOC_FLAGS_MEMORY_HANDLE_PROVIDED |
254              NVOS32_ALLOC_FLAGS_MAP_NOT_REQUIRED);
255 
256     if (DRF_VAL(OS02, _FLAGS, _ALLOC_USER_READ_ONLY, pApi->flags))
257         attr2 = FLD_SET_DRF(OS32, _ATTR2, _PROTECTION_USER, _READ_ONLY, attr2);
258 
259     // Currently CPU-RO memory implies GPU-RO as well
260     if (DRF_VAL(OS02, _FLAGS, _ALLOC_DEVICE_READ_ONLY, pApi->flags) ||
261         DRF_VAL(OS02, _FLAGS, _ALLOC_USER_READ_ONLY, pApi->flags))
262         attr2 = FLD_SET_DRF(OS32, _ATTR2, _PROTECTION_DEVICE, _READ_ONLY, attr2);
263 
264     pVidHeapParams->data.AllocOsDesc.hMemory = pApi->hObjectNew;
265     pVidHeapParams->data.AllocOsDesc.flags = flags;
266     pVidHeapParams->data.AllocOsDesc.attr = attr;
267     pVidHeapParams->data.AllocOsDesc.attr2 = attr2;
268     pVidHeapParams->data.AllocOsDesc.descriptor = pApi->pMemory;
269     pVidHeapParams->data.AllocOsDesc.limit = pApi->limit;
270     pVidHeapParams->data.AllocOsDesc.descriptorType = NVOS32_DESCRIPTOR_TYPE_VIRTUAL_ADDRESS;
271 
272     RmCreateOsDescriptor(pVidHeapParams, secInfo);
273 
274     pApi->status = pVidHeapParams->status;
275 
276     portMemFree(pVidHeapParams);
277 
278 done:
279     if (rmStatus != NV_OK)
280         pApi->status = rmStatus;
281 }
282 
283 ct_assert(NV_OFFSETOF(NVOS21_PARAMETERS, hRoot) == NV_OFFSETOF(NVOS64_PARAMETERS, hRoot));
284 ct_assert(NV_OFFSETOF(NVOS21_PARAMETERS, hObjectParent) == NV_OFFSETOF(NVOS64_PARAMETERS, hObjectParent));
285 ct_assert(NV_OFFSETOF(NVOS21_PARAMETERS, hObjectNew) == NV_OFFSETOF(NVOS64_PARAMETERS, hObjectNew));
286 ct_assert(NV_OFFSETOF(NVOS21_PARAMETERS, hClass) == NV_OFFSETOF(NVOS64_PARAMETERS, hClass));
287 ct_assert(NV_OFFSETOF(NVOS21_PARAMETERS, pAllocParms) == NV_OFFSETOF(NVOS64_PARAMETERS, pAllocParms));
288 
289 NV_STATUS RmIoctl(
290     nv_state_t  *nv,
291     nv_file_private_t *nvfp,
292     NvU32        cmd,
293     void        *data,
294     NvU32        dataSize
295 )
296 {
297     NV_STATUS            rmStatus = NV_ERR_GENERIC;
298     API_SECURITY_INFO    secInfo = { };
299 
300     secInfo.privLevel = osIsAdministrator() ? RS_PRIV_LEVEL_USER_ROOT : RS_PRIV_LEVEL_USER;
301     secInfo.paramLocation = PARAM_LOCATION_USER;
302     secInfo.pProcessToken = NULL;
303     secInfo.gpuOsInfo = NULL;
304     secInfo.clientOSInfo = nvfp->ctl_nvfp;
305     if (secInfo.clientOSInfo == NULL)
306         secInfo.clientOSInfo = nvfp;
307 
308     switch (cmd)
309     {
310         case NV_ESC_RM_ALLOC_MEMORY:
311         {
312             nv_ioctl_nvos02_parameters_with_fd *pApi;
313             NVOS02_PARAMETERS *pParms;
314 
315             pApi = data;
316             pParms = &pApi->params;
317 
318             NV_ACTUAL_DEVICE_ONLY(nv);
319 
320             if (dataSize != sizeof(nv_ioctl_nvos02_parameters_with_fd))
321             {
322                 rmStatus = NV_ERR_INVALID_ARGUMENT;
323                 goto done;
324             }
325 
326             if (pParms->hClass == NV01_MEMORY_SYSTEM_OS_DESCRIPTOR)
327                 RmAllocOsDescriptor(pParms, secInfo);
328             else
329             {
330                 NvU32 flags = pParms->flags;
331 
332                 Nv01AllocMemoryWithSecInfo(pParms, secInfo);
333 
334                 //
335                 // If the system memory is going to be mapped immediately,
336                 // create the mmap context for it now.
337                 //
338                 if ((pParms->hClass == NV01_MEMORY_SYSTEM) &&
339                     (!FLD_TEST_DRF(OS02, _FLAGS, _ALLOC, _NONE, flags)) &&
340                     (!FLD_TEST_DRF(OS02, _FLAGS, _MAPPING, _NO_MAP, flags)) &&
341                     (pParms->status == NV_OK))
342                 {
343                     if (rm_create_mmap_context(pParms->hRoot,
344                             pParms->hObjectParent, pParms->hObjectNew,
345                             pParms->pMemory, pParms->limit + 1, 0,
346                             NV_MEMORY_DEFAULT,
347                             pApi->fd) != NV_OK)
348                     {
349                         NV_PRINTF(LEVEL_WARNING,
350                                   "could not create mmap context for %p\n",
351                                   NvP64_VALUE(pParms->pMemory));
352                         rmStatus = NV_ERR_INVALID_ARGUMENT;
353                         goto done;
354                     }
355                 }
356             }
357 
358             break;
359         }
360 
361         case NV_ESC_RM_ALLOC_OBJECT:
362         {
363             NVOS05_PARAMETERS *pApi = data;
364 
365             NV_CTL_DEVICE_ONLY(nv);
366 
367             if (dataSize != sizeof(NVOS05_PARAMETERS))
368             {
369                 rmStatus = NV_ERR_INVALID_ARGUMENT;
370                 goto done;
371             }
372 
373             Nv01AllocObjectWithSecInfo(pApi, secInfo);
374             break;
375         }
376 
377         case NV_ESC_RM_ALLOC:
378         {
379             NVOS21_PARAMETERS *pApi = data;
380             NVOS64_PARAMETERS *pApiAccess = data;
381             NvBool bAccessApi = (dataSize == sizeof(NVOS64_PARAMETERS));
382 
383             if ((dataSize != sizeof(NVOS21_PARAMETERS)) &&
384                 (dataSize != sizeof(NVOS64_PARAMETERS)))
385             {
386                 rmStatus = NV_ERR_INVALID_ARGUMENT;
387                 goto done;
388             }
389 
390             switch (pApi->hClass)
391             {
392                 case NV01_ROOT:
393                 case NV01_ROOT_CLIENT:
394                 case NV01_ROOT_NON_PRIV:
395                 {
396                     NV_CTL_DEVICE_ONLY(nv);
397 
398                     // Force userspace client allocations to be the _CLIENT class.
399                     pApi->hClass = NV01_ROOT_CLIENT;
400                     break;
401                 }
402                 case NV01_EVENT:
403                 case NV01_EVENT_OS_EVENT:
404                 case NV01_EVENT_KERNEL_CALLBACK:
405                 case NV01_EVENT_KERNEL_CALLBACK_EX:
406                 {
407                     break;
408                 }
409                 default:
410                 {
411                     NV_CTL_DEVICE_ONLY(nv);
412                     break;
413                 }
414             }
415 
416             if (!bAccessApi)
417             {
418                 Nv04AllocWithSecInfo(pApi, secInfo);
419             }
420             else
421             {
422                 Nv04AllocWithAccessSecInfo(pApiAccess, secInfo);
423             }
424 
425             break;
426         }
427 
428         case NV_ESC_RM_FREE:
429         {
430             NVOS00_PARAMETERS *pApi = data;
431 
432             NV_CTL_DEVICE_ONLY(nv);
433 
434             if (dataSize != sizeof(NVOS00_PARAMETERS))
435             {
436                 rmStatus = NV_ERR_INVALID_ARGUMENT;
437                 goto done;
438             }
439 
440             Nv01FreeWithSecInfo(pApi, secInfo);
441 
442             if (pApi->status == NV_OK &&
443                 pApi->hObjectOld == pApi->hRoot)
444             {
445                 rm_client_free_os_events(pApi->hRoot);
446             }
447 
448             break;
449         }
450 
451         case NV_ESC_RM_VID_HEAP_CONTROL:
452         {
453             NVOS32_PARAMETERS *pApi = data;
454 
455             NV_CTL_DEVICE_ONLY(nv);
456 
457             if (dataSize != sizeof(NVOS32_PARAMETERS))
458             {
459                 rmStatus = NV_ERR_INVALID_ARGUMENT;
460                 goto done;
461             }
462 
463             if (pApi->function == NVOS32_FUNCTION_ALLOC_OS_DESCRIPTOR)
464                 RmCreateOsDescriptor(pApi, secInfo);
465             else
466                 Nv04VidHeapControlWithSecInfo(pApi, secInfo);
467 
468             break;
469         }
470 
471         case NV_ESC_RM_I2C_ACCESS:
472         {
473             NVOS_I2C_ACCESS_PARAMS *pApi = data;
474 
475             NV_ACTUAL_DEVICE_ONLY(nv);
476 
477             if (dataSize != sizeof(NVOS_I2C_ACCESS_PARAMS))
478             {
479                 rmStatus = NV_ERR_INVALID_ARGUMENT;
480                 goto done;
481             }
482 
483             Nv04I2CAccessWithSecInfo(pApi, secInfo);
484             break;
485         }
486 
487         case NV_ESC_RM_IDLE_CHANNELS:
488         {
489             NVOS30_PARAMETERS *pApi = data;
490 
491             NV_CTL_DEVICE_ONLY(nv);
492 
493             if (dataSize != sizeof(NVOS30_PARAMETERS))
494             {
495                 rmStatus = NV_ERR_INVALID_ARGUMENT;
496                 goto done;
497             }
498 
499             Nv04IdleChannelsWithSecInfo(pApi, secInfo);
500             break;
501         }
502 
503         case NV_ESC_RM_MAP_MEMORY:
504         {
505             nv_ioctl_nvos33_parameters_with_fd *pApi;
506             NVOS33_PARAMETERS *pParms;
507 
508             pApi = data;
509             pParms = &pApi->params;
510 
511             NV_CTL_DEVICE_ONLY(nv);
512 
513             if (dataSize != sizeof(nv_ioctl_nvos33_parameters_with_fd))
514             {
515                 rmStatus = NV_ERR_INVALID_ARGUMENT;
516                 goto done;
517             }
518 
519             // Don't allow userspace to override the caching type
520             pParms->flags = FLD_SET_DRF(OS33, _FLAGS, _CACHING_TYPE, _DEFAULT, pParms->flags);
521             Nv04MapMemoryWithSecInfo(pParms, secInfo);
522 
523             if (pParms->status == NV_OK)
524             {
525                 pParms->status = rm_create_mmap_context(pParms->hClient,
526                                  pParms->hDevice, pParms->hMemory,
527                                  pParms->pLinearAddress, pParms->length,
528                                  pParms->offset,
529                                  DRF_VAL(OS33, _FLAGS, _CACHING_TYPE, pParms->flags),
530                                  pApi->fd);
531                 if (pParms->status != NV_OK)
532                 {
533                     NVOS34_PARAMETERS params;
534                     portMemSet(&params, 0, sizeof(NVOS34_PARAMETERS));
535                     params.hClient        = pParms->hClient;
536                     params.hDevice        = pParms->hDevice;
537                     params.hMemory        = pParms->hMemory;
538                     params.pLinearAddress = pParms->pLinearAddress;
539                     params.flags          = pParms->flags;
540                     Nv04UnmapMemoryWithSecInfo(&params, secInfo);
541                 }
542             }
543             break;
544         }
545 
546         case NV_ESC_RM_UNMAP_MEMORY:
547         {
548             NVOS34_PARAMETERS *pApi = data;
549 
550             NV_CTL_DEVICE_ONLY(nv);
551 
552             if (dataSize != sizeof(NVOS34_PARAMETERS))
553             {
554                 rmStatus = NV_ERR_INVALID_ARGUMENT;
555                 goto done;
556             }
557 
558             Nv04UnmapMemoryWithSecInfo(pApi, secInfo);
559             break;
560         }
561 
562         case NV_ESC_RM_ACCESS_REGISTRY:
563         {
564             NVOS38_PARAMETERS *pApi = data;
565 
566             NV_CTL_DEVICE_ONLY(nv);
567 
568             if (dataSize != sizeof(NVOS38_PARAMETERS))
569             {
570                 rmStatus = NV_ERR_INVALID_ARGUMENT;
571                 goto done;
572             }
573 
574             pApi->status = rm_access_registry(pApi->hClient,
575                                               pApi->hObject,
576                                               pApi->AccessType,
577                                               pApi->pDevNode,
578                                               pApi->DevNodeLength,
579                                               pApi->pParmStr,
580                                               pApi->ParmStrLength,
581                                               pApi->pBinaryData,
582                                               &pApi->BinaryDataLength,
583                                               &pApi->Data,
584                                               &pApi->Entry);
585             break;
586         }
587 
588         case NV_ESC_RM_ALLOC_CONTEXT_DMA2:
589         {
590             NVOS39_PARAMETERS *pApi = data;
591 
592             NV_CTL_DEVICE_ONLY(nv);
593 
594             if (dataSize != sizeof(NVOS39_PARAMETERS))
595             {
596                 rmStatus = NV_ERR_INVALID_ARGUMENT;
597                 goto done;
598             }
599 
600             Nv04AllocContextDmaWithSecInfo(pApi, secInfo);
601             break;
602         }
603 
604         case NV_ESC_RM_BIND_CONTEXT_DMA:
605         {
606             NVOS49_PARAMETERS *pApi = data;
607 
608             NV_CTL_DEVICE_ONLY(nv);
609 
610             if (dataSize != sizeof(NVOS49_PARAMETERS))
611             {
612                 rmStatus = NV_ERR_INVALID_ARGUMENT;
613                 goto done;
614             }
615 
616             Nv04BindContextDmaWithSecInfo(pApi, secInfo);
617             break;
618         }
619 
620         case NV_ESC_RM_MAP_MEMORY_DMA:
621         {
622             NVOS46_PARAMETERS *pApi = data;
623 
624             NV_CTL_DEVICE_ONLY(nv);
625 
626             if (dataSize != sizeof(NVOS46_PARAMETERS))
627             {
628                 rmStatus = NV_ERR_INVALID_ARGUMENT;
629                 goto done;
630             }
631 
632             Nv04MapMemoryDmaWithSecInfo(pApi, secInfo);
633             break;
634         }
635 
636         case NV_ESC_RM_UNMAP_MEMORY_DMA:
637         {
638             NVOS47_PARAMETERS *pApi = data;
639 
640             NV_CTL_DEVICE_ONLY(nv);
641 
642             if (dataSize != sizeof(NVOS47_PARAMETERS))
643             {
644                 rmStatus = NV_ERR_INVALID_ARGUMENT;
645                 goto done;
646             }
647 
648             Nv04UnmapMemoryDmaWithSecInfo(pApi, secInfo);
649             break;
650         }
651 
652         case NV_ESC_RM_DUP_OBJECT:
653         {
654             NVOS55_PARAMETERS *pApi = data;
655 
656             NV_CTL_DEVICE_ONLY(nv);
657 
658             if (dataSize != sizeof(NVOS55_PARAMETERS))
659             {
660                 rmStatus = NV_ERR_INVALID_ARGUMENT;
661                 goto done;
662             }
663 
664             Nv04DupObjectWithSecInfo(pApi, secInfo);
665             break;
666         }
667 
668         case NV_ESC_RM_SHARE:
669         {
670             NVOS57_PARAMETERS *pApi = data;
671 
672             NV_CTL_DEVICE_ONLY(nv);
673 
674             if (dataSize != sizeof(NVOS57_PARAMETERS))
675             {
676                 rmStatus = NV_ERR_INVALID_ARGUMENT;
677                 goto done;
678             }
679 
680             Nv04ShareWithSecInfo(pApi, secInfo);
681             break;
682         }
683 
684         case NV_ESC_ALLOC_OS_EVENT:
685         {
686             nv_ioctl_alloc_os_event_t *pApi = data;
687 
688             if (dataSize != sizeof(nv_ioctl_alloc_os_event_t))
689             {
690                 rmStatus = NV_ERR_INVALID_ARGUMENT;
691                 goto done;
692             }
693 
694             pApi->Status = rm_alloc_os_event(pApi->hClient,
695                                              nvfp,
696                                              pApi->fd);
697             break;
698         }
699 
700         case NV_ESC_FREE_OS_EVENT:
701         {
702             nv_ioctl_free_os_event_t *pApi = data;
703 
704             if (dataSize != sizeof(nv_ioctl_free_os_event_t))
705             {
706                 rmStatus = NV_ERR_INVALID_ARGUMENT;
707                 goto done;
708             }
709 
710             pApi->Status = rm_free_os_event(pApi->hClient, pApi->fd);
711             break;
712         }
713 
714         case NV_ESC_RM_GET_EVENT_DATA:
715         {
716             NVOS41_PARAMETERS *pApi = data;
717 
718             if (dataSize != sizeof(NVOS41_PARAMETERS))
719             {
720                 rmStatus = NV_ERR_INVALID_ARGUMENT;
721                 goto done;
722             }
723 
724             pApi->status = rm_get_event_data(nvfp,
725                                              pApi->pEvent,
726                                              &pApi->MoreEvents);
727             break;
728         }
729 
730         case NV_ESC_STATUS_CODE:
731         {
732             nv_state_t *pNv;
733             nv_ioctl_status_code_t *pApi = data;
734 
735             NV_CTL_DEVICE_ONLY(nv);
736 
737             if (dataSize != sizeof(nv_ioctl_status_code_t))
738             {
739                 rmStatus = NV_ERR_INVALID_ARGUMENT;
740                 goto done;
741             }
742 
743             pNv = nv_get_adapter_state(pApi->domain, pApi->bus, pApi->slot);
744             if (pNv == NULL)
745             {
746                 rmStatus = NV_ERR_INVALID_ARGUMENT;
747                 goto done;
748             }
749 
750             rmStatus = rm_get_adapter_status(pNv, &pApi->status);
751 
752             if (rmStatus != NV_OK)
753                 goto done;
754 
755             break;
756         }
757 
758         case NV_ESC_RM_CONTROL:
759         {
760             NVOS54_PARAMETERS *pApi = data;
761             void *priv = NULL;
762             nv_file_private_t *dev_nvfp = NULL;
763             NvS32 fd;
764 
765             NV_CTL_DEVICE_ONLY(nv);
766 
767             if (dataSize != sizeof(NVOS54_PARAMETERS))
768             {
769                 rmStatus = NV_ERR_INVALID_ARGUMENT;
770                 goto done;
771             }
772 
773             if (RmIsDeviceRefNeeded(pApi))
774             {
775                 rmStatus = RmGetDeviceFd(pApi, &fd);
776                 if (rmStatus != NV_OK)
777                 {
778                     goto done;
779                 }
780 
781                 dev_nvfp = nv_get_file_private(fd, NV_FALSE, &priv);
782                 if (dev_nvfp == NULL)
783                 {
784                     rmStatus = NV_ERR_INVALID_DEVICE;
785                     goto done;
786                 }
787 
788                 // Check to avoid cyclic dependency with NV_ESC_REGISTER_FD
789                 if (!portAtomicCompareAndSwapU32(&dev_nvfp->register_or_refcount,
790                                                  NVFP_TYPE_REFCOUNTED,
791                                                  NVFP_TYPE_NONE))
792                 {
793                     // Is this already refcounted...
794                     if (dev_nvfp->register_or_refcount != NVFP_TYPE_REFCOUNTED)
795                     {
796                         nv_put_file_private(priv);
797                         rmStatus = NV_ERR_IN_USE;
798                         goto done;
799                     }
800                 }
801 
802                 secInfo.gpuOsInfo = priv;
803             }
804 
805             Nv04ControlWithSecInfo(pApi, secInfo);
806 
807             if ((pApi->status != NV_OK) && (priv != NULL))
808             {
809                 //
810                 // No need to reset `register_or_refcount` as it might be set
811                 // for previous successful calls. We let it clear with FD close.
812                 //
813                 nv_put_file_private(priv);
814 
815                 secInfo.gpuOsInfo = NULL;
816             }
817 
818             break;
819         }
820 
821         case NV_ESC_RM_UPDATE_DEVICE_MAPPING_INFO:
822         {
823             NVOS56_PARAMETERS *pApi = data;
824             void *pOldCpuAddress;
825             void *pNewCpuAddress;
826 
827             NV_CTL_DEVICE_ONLY(nv);
828 
829             if (dataSize != sizeof(NVOS56_PARAMETERS))
830             {
831                 rmStatus = NV_ERR_INVALID_ARGUMENT;
832                 goto done;
833             }
834 
835             pOldCpuAddress = NvP64_VALUE(pApi->pOldCpuAddress);
836             pNewCpuAddress = NvP64_VALUE(pApi->pNewCpuAddress);
837 
838             pApi->status = rm_update_device_mapping_info(pApi->hClient,
839                                                          pApi->hDevice,
840                                                          pApi->hMemory,
841                                                          pOldCpuAddress,
842                                                          pNewCpuAddress);
843             break;
844         }
845 
846         case NV_ESC_RM_NVLOG_CTRL:
847         {
848             NV_NVLOG_CTRL_PARAMS *pParams = data;
849 
850             NV_CTL_DEVICE_ONLY(nv);
851 
852             if (!osIsAdministrator())
853             {
854                 rmStatus = NV_ERR_INSUFFICIENT_PERMISSIONS;
855                 pParams->status = rmStatus;
856                 goto done;
857             }
858 
859             switch (pParams->ctrl)
860             {
861                 // Do not use NVOC _DISPATCH here as it dereferences NULL RmClientResource*
862                 case NV0000_CTRL_CMD_NVD_GET_NVLOG_INFO:
863                     rmStatus = cliresCtrlCmdNvdGetNvlogInfo_IMPL(NULL, &pParams->params.getNvlogInfo);
864                     break;
865                 case NV0000_CTRL_CMD_NVD_GET_NVLOG_BUFFER_INFO:
866                     rmStatus = cliresCtrlCmdNvdGetNvlogBufferInfo_IMPL(NULL, &pParams->params.getNvlogBufferInfo);
867                     break;
868                 case NV0000_CTRL_CMD_NVD_GET_NVLOG:
869                     rmStatus = cliresCtrlCmdNvdGetNvlog_IMPL(NULL, &pParams->params.getNvlog);
870                     break;
871                 default:
872                     rmStatus = NV_ERR_NOT_SUPPORTED;
873                     break;
874             }
875 
876             pParams->status = rmStatus;
877             goto done;
878         }
879 
880         case NV_ESC_REGISTER_FD:
881         {
882             nv_ioctl_register_fd_t *params = data;
883             void *priv = NULL;
884             nv_file_private_t *ctl_nvfp;
885 
886             if (dataSize != sizeof(nv_ioctl_register_fd_t))
887             {
888                 rmStatus = NV_ERR_INVALID_ARGUMENT;
889                 goto done;
890             }
891 
892             // LOCK: acquire API lock
893             rmStatus = rmapiLockAcquire(API_LOCK_FLAGS_NONE, RM_LOCK_MODULES_OSAPI);
894             if (rmStatus != NV_OK)
895                 goto done;
896 
897             // If there is already a ctl fd registered on this nvfp, fail.
898             if (nvfp->ctl_nvfp != NULL)
899             {
900                 // UNLOCK: release API lock
901                 rmapiLockRelease();
902                 rmStatus = NV_ERR_INVALID_STATE;
903                 goto done;
904             }
905 
906             //
907             // Note that this call is valid for both "actual" devices and ctrl
908             // devices.  In particular, NV_ESC_ALLOC_OS_EVENT can be used with
909             // both types of devices.
910             // But, the ctl_fd passed in should always correspond to a control FD.
911             //
912             ctl_nvfp = nv_get_file_private(params->ctl_fd,
913                                            NV_TRUE, /* require ctl fd */
914                                            &priv);
915             if (ctl_nvfp == NULL)
916             {
917                 // UNLOCK: release API lock
918                 rmapiLockRelease();
919                 rmStatus = NV_ERR_INVALID_ARGUMENT;
920                 goto done;
921             }
922 
923             // Disallow self-referential links, and disallow links to FDs that
924             // themselves have a link.
925             if ((ctl_nvfp == nvfp) || (ctl_nvfp->ctl_nvfp != NULL))
926             {
927                 nv_put_file_private(priv);
928                 // UNLOCK: release API lock
929                 rmapiLockRelease();
930                 rmStatus = NV_ERR_INVALID_ARGUMENT;
931                 goto done;
932             }
933 
934             // Check to avoid cyclic dependency with device refcounting
935             if (!portAtomicCompareAndSwapU32(&nvfp->register_or_refcount,
936                                              NVFP_TYPE_REGISTERED,
937                                              NVFP_TYPE_NONE))
938             {
939                 nv_put_file_private(priv);
940                 // UNLOCK: release API lock
941                 rmapiLockRelease();
942                 rmStatus = NV_ERR_IN_USE;
943                 goto done;
944             }
945 
946             //
947             // nvfp->ctl_nvfp is read outside the lock, so set it atomically.
948             // Note that once set, this can never be removed until the fd
949             // associated with nvfp is closed.  We hold on to 'priv' until the
950             // fd is closed, too, to ensure that the fd associated with
951             // ctl_nvfp remains valid.
952             //
953             portAtomicSetSize(&nvfp->ctl_nvfp, ctl_nvfp);
954             nvfp->ctl_nvfp_priv = priv;
955 
956             // UNLOCK: release API lock
957             rmapiLockRelease();
958 
959             // NOTE: nv_put_file_private(priv) is not called here.  It MUST be
960             // called during cleanup of this nvfp.
961             rmStatus = NV_OK;
962             break;
963         }
964 
965         default:
966         {
967             NV_PRINTF(LEVEL_ERROR, "unknown NVRM ioctl command: 0x%x\n", cmd);
968             goto done;
969         }
970     }
971 
972     rmStatus = NV_OK;
973 done:
974 
975     return rmStatus;
976 }
977