1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2015-2023 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 #include "nvlog_inc.h"
26 #include "resserv/resserv.h"
27 #include "resserv/rs_client.h"
28 #include "resserv/rs_server.h"
29 
30 #if !(RS_STANDALONE)
31 #include "os/os.h"
32 #include "resserv/rs_access_map.h"
33 #endif
34 
35 typedef enum
36 {
37     ALLOC_NEW_RESOURCE,
38     ALLOC_SHARED_RESOURCE
39 } ALLOC_TYPE;
40 
41 /**
42  * Allocate a new or shared resource in RM for this client
43  * @param[in]       pClient This client
44  * @param[in]       pServer The resource server instance
45  * @param[in]       pParams Parameters for the resource allocation
46  * @param[in,out]   phResource Server will assign a handle if it is 0
47  */
48 static NV_STATUS _clientAllocResourceHelper(RsClient *pClient, RsServer *pServer,
49                                             RS_RES_ALLOC_PARAMS_INTERNAL *pParams,
50                                             NvHandle *phResource);
51 
52 /**
53  * Add a resource reference to the client's resource hashmap
54  * @param[in] pClient This client
55  * @param[in] pServer The resource server that owns the resource ref
56  * @param[in] pParentRef   The resource's parent reference
57  * @param[in] hResource The resource's handle
58  * @param[in] classId   The resource's class
59  * @param[out] ppResourceRef The new resource reference
60  */
61 static NV_STATUS _clientConstructResourceRef(RsClient *pClient, RsServer *pServer, RsResourceRef *pParentRef,
62                                              NvHandle hResource, NvU32 classId, RsResourceRef **ppResourceRef);
63 
64 /**
65  * Release all CPU address mappings that reference this resource
66  *
67  * @param[in] pClient Client that owns the resource
68  * @param[in] pCallContext Caller information (which includes the resource reference
69  *                         whose mapping back references will be freed)
70  * @param[in] pLockInfo Information about which locks are already held, for recursive calls
71  */
72 static NV_STATUS _clientUnmapBackRefMappings(RsClient *pClient, CALL_CONTEXT *pCallContext, RS_LOCK_INFO *pLockInfo);
73 
74 static void _clientUnmapInterMappings(RsClient *pClient, CALL_CONTEXT *pCallContext, RS_LOCK_INFO *pLockInfo);
75 static void _clientUnmapInterBackRefMappings(RsClient *pClient, CALL_CONTEXT *pCallContext, RS_LOCK_INFO *pLockInfo);
76 
77 NV_STATUS
clientConstruct_IMPL(RsClient * pClient,PORT_MEM_ALLOCATOR * pAllocator,RS_RES_ALLOC_PARAMS_INTERNAL * pParams)78 clientConstruct_IMPL
79 (
80     RsClient *pClient,
81     PORT_MEM_ALLOCATOR *pAllocator,
82     RS_RES_ALLOC_PARAMS_INTERNAL *pParams
83 )
84 {
85     NV_STATUS status;
86     CLIENT_TYPE type;
87 
88     if (pParams->pSecInfo->privLevel >= RS_PRIV_LEVEL_KERNEL)
89         type = CLIENT_TYPE_KERNEL;
90     else
91         type = CLIENT_TYPE_USER;
92 
93     pClient->type = type;
94     pClient->hClient = pParams->hClient;
95 
96     mapInit(&pClient->resourceMap, pAllocator);
97     listInitIntrusive(&pClient->pendingFreeList);
98 
99     listInit(&pClient->accessBackRefList, pAllocator);
100 
101     pClient->handleGenIdx = 0;
102     status = clientSetHandleGenerator(pClient, 0, 0);
103     if (status != NV_OK)
104         return status;
105 
106     pClient->bActive = NV_TRUE;
107 
108     status = clientSetRestrictedRange(pClient, 0, 0);
109     if (status != NV_OK)
110         return status;
111 
112     return NV_OK;
113 }
114 
115 NV_STATUS
clientSetHandleGenerator_IMPL(RsClient * pClient,NvHandle handleRangeStart,NvHandle handleRangeSize)116 clientSetHandleGenerator_IMPL
117 (
118     RsClient *pClient,
119     NvHandle handleRangeStart,
120     NvHandle handleRangeSize
121 )
122 {
123     //
124     // on vGPU, when client uses RM allocated handles, post allocation of rmclient NV01_ROOT,
125     // NV01_DEVICE_0 is allocated which increment the handleGenIdx to 0x1.
126     // In order to avoid the handle clash, we split the default RM handle ranges between Guest RM
127     // (0xcaf00000, 0xcaf3ffff) and host RM (0xcaf40000, 0xcaf80000).
128     // Hence, we should take this overriding into consideration when the ranges over the default
129     // RM handle ranges.
130     //
131     NvBool bShrinkUnusedRange = ((pClient->handleRangeStart == handleRangeStart) &&
132                                  (pClient->handleGenIdx <= handleRangeSize));
133 
134     if (!((pClient->handleGenIdx == 0) || bShrinkUnusedRange))
135     {
136         return NV_ERR_INVALID_STATE;
137     }
138 
139     if ((handleRangeStart == 0) && (handleRangeSize == 0))
140     {
141         pClient->handleRangeStart = RS_UNIQUE_HANDLE_BASE;
142         pClient->handleRangeSize = RS_UNIQUE_HANDLE_RANGE;
143     }
144     else if ((handleRangeStart != 0) && (handleRangeSize != 0))
145     {
146         pClient->handleRangeStart = handleRangeStart;
147         pClient->handleRangeSize = handleRangeSize;
148     }
149     else
150     {
151         return NV_ERR_INVALID_PARAMETER;
152     }
153 
154     return NV_OK;
155 }
156 
clientCanShareResource_IMPL(RsClient * pClient,RsResourceRef * pResourceRef,RS_SHARE_POLICY * pSharePolicy,CALL_CONTEXT * pCallContext)157 NV_STATUS clientCanShareResource_IMPL
158 (
159     RsClient *pClient,
160     RsResourceRef *pResourceRef,
161     RS_SHARE_POLICY *pSharePolicy,
162     CALL_CONTEXT *pCallContext
163 )
164 {
165     NV_STATUS status = NV_OK;
166 
167     RS_ACCESS_MASK rightsNeeded;
168     RS_ACCESS_MASK *pRightsHeld;
169 
170     //
171     // If sharing, check that the client has the rights it is trying to share
172     // Revoking does not require this to allow revoking all rights without checking
173     //
174     if (!(pSharePolicy->action & RS_SHARE_ACTION_FLAG_REVOKE))
175     {
176         status = rsAccessCheckRights(pResourceRef, pClient, &pSharePolicy->accessMask);
177         if (status == NV_ERR_INSUFFICIENT_PERMISSIONS)
178         {
179             // Attempt to grant rights which aren't already owned
180             portMemCopy(&rightsNeeded, sizeof(rightsNeeded),
181                         &pSharePolicy->accessMask, sizeof(pSharePolicy->accessMask));
182 
183             pRightsHeld = rsAccessLookup(pResourceRef, pClient);
184             if (pRightsHeld != NULL)
185             {
186                 // Skip trying to grant rights already held
187                 RS_ACCESS_MASK_SUBTRACT(&rightsNeeded, pRightsHeld);
188             }
189 
190             status = rsAccessGrantRights(pResourceRef, pCallContext, pClient,
191                                          &rightsNeeded,    // pRightsRequested
192                                          NULL,             // pRightsRequired
193                                          NULL);            // pAllocParams
194         }
195     }
196 
197     return status;
198 }
199 
200 NV_STATUS
clientShareResource_IMPL(RsClient * pClient,RsResourceRef * pResourceRef,RS_SHARE_POLICY * pSharePolicy,CALL_CONTEXT * pCallContext)201 clientShareResource_IMPL
202 (
203     RsClient *pClient,
204     RsResourceRef *pResourceRef,
205     RS_SHARE_POLICY *pSharePolicy,
206     CALL_CONTEXT *pCallContext
207 )
208 {
209     RsServer *pServer = NULL;
210     RsShareList *pActiveList;
211     NV_STATUS status;
212 
213     status = clientCanShareResource(pClient, pResourceRef, pSharePolicy, pCallContext);
214     if (status != NV_OK)
215         return status;
216 
217     if (!pResourceRef->bSharePolicyListModified)
218     {
219         if (pSharePolicy->action & RS_SHARE_ACTION_FLAG_COMPOSE)
220         {
221             if (pCallContext != NULL)
222                 pServer = pCallContext->pServer;
223 
224             pActiveList = rsAccessGetActiveShareList(pResourceRef, pServer);
225             status = rsShareListCopy(&pResourceRef->sharePolicyList, pActiveList);
226             if (status != NV_OK)
227                 return status;
228         }
229 
230         pResourceRef->bSharePolicyListModified = NV_TRUE;
231     }
232 
233     if (!(pSharePolicy->action & RS_SHARE_ACTION_FLAG_COMPOSE))
234     {
235         listClear(&pResourceRef->sharePolicyList);
236     }
237 
238     if (pSharePolicy->action & RS_SHARE_ACTION_FLAG_REVOKE)
239     {
240         rsShareListRemove(&pResourceRef->sharePolicyList, pSharePolicy, NULL);
241     }
242     else
243     {
244         status = rsShareListInsert(&pResourceRef->sharePolicyList, pSharePolicy, NULL);
245     }
246 
247     return status;
248 }
249 
250 NV_STATUS
clientShareResourceTargetClient_IMPL(RsClient * pClient,RsResourceRef * pResourceRef,RS_SHARE_POLICY * pSharePolicy,CALL_CONTEXT * pCallContext)251 clientShareResourceTargetClient_IMPL
252 (
253     RsClient *pClient,
254     RsResourceRef *pResourceRef,
255     RS_SHARE_POLICY *pSharePolicy,
256     CALL_CONTEXT *pCallContext
257 )
258 {
259     NV_STATUS       status;
260     RS_ACCESS_MASK *pCurrentRights;
261 
262     // Special case: This should only be called when share policy is for own client
263     NV_ASSERT(pSharePolicy->type == RS_SHARE_TYPE_CLIENT);
264     NV_ASSERT(pSharePolicy->target == pClient->hClient);
265 
266     status = clientCanShareResource(pClient, pResourceRef, pSharePolicy, pCallContext);
267     if (status != NV_OK)
268         return status;
269 
270     pCurrentRights = rsAccessLookup(pResourceRef, pClient);
271 
272     if (pSharePolicy->action & RS_SHARE_ACTION_FLAG_REVOKE)
273     {
274         RS_ACCESS_MASK_SUBTRACT(pCurrentRights, &pSharePolicy->accessMask);
275     }
276     else
277     {
278         RS_ACCESS_MASK_UNION(pCurrentRights, &pSharePolicy->accessMask);
279     }
280 
281     return NV_OK;
282 }
283 
284 NV_STATUS
clientSetRestrictedRange_IMPL(RsClient * pClient,NvHandle handleRangeStart,NvU32 handleRangeSize)285 clientSetRestrictedRange_IMPL
286 (
287     RsClient *pClient,
288     NvHandle handleRangeStart,
289     NvU32 handleRangeSize
290 )
291 {
292     NvHandle hFirst = handleRangeStart;
293     NvHandle hLast;
294 
295     // Only allow modification if we haven't generated any handles
296     if (pClient->handleGenIdx != 0)
297         return NV_ERR_INVALID_STATE;
298 
299     if (handleRangeSize == 0)
300     {
301         if (handleRangeStart != 0)
302             return NV_ERR_INVALID_PARAMETER;
303 
304         pClient->handleRestrictRange = NV_RANGE_EMPTY;
305         return NV_OK;
306     }
307 
308     // Wrapping-around the reserved range is not supported
309     if (!portSafeAddU32(hFirst, handleRangeSize-1, &hLast))
310         return NV_ERR_INVALID_REQUEST;
311 
312     pClient->handleRestrictRange = rangeMake(hFirst, hLast);
313 
314     return NV_OK;
315 }
316 
clientDestruct_IMPL(RsClient * pClient)317 void clientDestruct_IMPL
318 (
319     RsClient *pClient
320 )
321 {
322     NV_ASSERT(mapCount(&pClient->resourceMap) == 0);
323     mapDestroy(&pClient->resourceMap);
324 
325     NV_ASSERT(listCount(&pClient->accessBackRefList) == 0);
326     listDestroy(&pClient->accessBackRefList);
327 }
328 
329 NV_STATUS
clientGetResource_IMPL(RsClient * pClient,NvHandle hResource,NvU32 internalClassId,RsResource ** ppResource)330 clientGetResource_IMPL
331 (
332     RsClient *pClient,
333     NvHandle hResource,
334     NvU32 internalClassId,
335     RsResource **ppResource
336 )
337 {
338     NV_STATUS      status = NV_OK;
339     RsResourceRef *pResourceRef;
340     RsResource    *pResource;
341 
342     pResourceRef = mapFind(&pClient->resourceMap, hResource);
343     if (pResourceRef == NULL)
344     {
345         status = NV_ERR_OBJECT_NOT_FOUND;
346         pResource = NULL;
347         goto done;
348     }
349 
350     if (pResourceRef->internalClassId != internalClassId)
351     {
352         status = NV_ERR_INVALID_CLASS;
353         pResource = NULL;
354         goto done;
355     }
356 
357     pResource = pResourceRef->pResource;
358 
359 done:
360     if (ppResource != NULL)
361         *ppResource = pResource;
362 
363     return status;
364 }
365 
366 NV_STATUS
clientGetResourceByRef_IMPL(RsClient * pClient,RsResourceRef * pResourceRef,RsResource ** ppResource)367 clientGetResourceByRef_IMPL
368 (
369     RsClient *pClient,
370     RsResourceRef *pResourceRef,
371     RsResource **ppResource
372 )
373 {
374     if (ppResource != NULL)
375         *ppResource = pResourceRef->pResource;
376 
377     return NV_OK;
378 }
379 
380 NV_STATUS
clientGetResourceRef_IMPL(RsClient * pClient,NvHandle hResource,RsResourceRef ** ppResourceRef)381 clientGetResourceRef_IMPL
382 (
383     RsClient *pClient,
384     NvHandle hResource,
385     RsResourceRef **ppResourceRef
386 )
387 {
388     RsResourceRef *pResourceRef;
389 
390     pResourceRef = mapFind(&pClient->resourceMap, hResource);
391     if (pResourceRef == NULL)
392         return NV_ERR_OBJECT_NOT_FOUND;
393 
394     if (ppResourceRef != NULL)
395         *ppResourceRef = pResourceRef;
396 
397     return NV_OK;
398 }
399 
400 NV_STATUS
clientGetResourceRefWithAccess_IMPL(RsClient * pClient,NvHandle hResource,const RS_ACCESS_MASK * pRightsRequired,RsResourceRef ** ppResourceRef)401 clientGetResourceRefWithAccess_IMPL
402 (
403     RsClient *pClient,
404     NvHandle hResource,
405     const RS_ACCESS_MASK *pRightsRequired,
406     RsResourceRef **ppResourceRef
407 )
408 {
409     NV_STATUS status;
410     RsResourceRef *pResourceRef;
411 
412     status = clientGetResourceRef(pClient, hResource, &pResourceRef);
413     if (status != NV_OK)
414         return status;
415 
416     status = rsAccessCheckRights(pResourceRef, pClient, pRightsRequired);
417     if (status != NV_OK)
418         return status;
419 
420     if (ppResourceRef != NULL)
421         *ppResourceRef = pResourceRef;
422 
423     return NV_OK;
424 }
425 
426 NV_STATUS
clientGetResourceRefByType_IMPL(RsClient * pClient,NvHandle hResource,NvU32 internalClassId,RsResourceRef ** ppResourceRef)427 clientGetResourceRefByType_IMPL
428 (
429     RsClient *pClient,
430     NvHandle hResource,
431     NvU32 internalClassId,
432     RsResourceRef **ppResourceRef
433 )
434 {
435     NV_STATUS status;
436     RsResourceRef *pResourceRef;
437 
438     status = clientGetResourceRef(pClient, hResource, &pResourceRef);
439     if (status != NV_OK)
440         return status;
441 
442     if (pResourceRef->internalClassId != internalClassId)
443         return NV_ERR_INVALID_OBJECT_HANDLE;
444 
445     if (ppResourceRef != NULL)
446         *ppResourceRef = pResourceRef;
447 
448     return NV_OK;
449 }
450 
451 NV_STATUS
clientValidate_IMPL(RsClient * pClient,const API_SECURITY_INFO * pSecInfo)452 clientValidate_IMPL
453 (
454     RsClient                *pClient,
455     const API_SECURITY_INFO *pSecInfo
456 )
457 {
458     return NV_OK;
459 }
460 
461 RS_PRIV_LEVEL
clientGetCachedPrivilege_IMPL(RsClient * pClient)462 clientGetCachedPrivilege_IMPL
463 (
464     RsClient *pClient
465 )
466 {
467     // Non-functional, base class stubs
468     return RS_PRIV_LEVEL_USER;
469 }
470 
471 NvBool
clientIsAdmin_IMPL(RsClient * pClient,RS_PRIV_LEVEL privLevel)472 clientIsAdmin_IMPL
473 (
474     RsClient *pClient,
475     RS_PRIV_LEVEL privLevel
476 )
477 {
478     // Non-functional, base class stubs
479     return NV_FALSE;
480 }
481 
482 NV_STATUS
clientAllocResource_IMPL(RsClient * pClient,RsServer * pServer,RS_RES_ALLOC_PARAMS_INTERNAL * pParams)483 clientAllocResource_IMPL
484 (
485     RsClient   *pClient,
486     RsServer   *pServer,
487     RS_RES_ALLOC_PARAMS_INTERNAL *pParams
488 )
489 {
490     return _clientAllocResourceHelper(pClient, pServer, pParams, &pParams->hResource);
491 }
492 
493 NV_STATUS
clientCopyResource_IMPL(RsClient * pClient,RsServer * pServer,RS_RES_DUP_PARAMS_INTERNAL * pParams)494 clientCopyResource_IMPL
495 (
496     RsClient   *pClient,
497     RsServer   *pServer,
498     RS_RES_DUP_PARAMS_INTERNAL *pParams
499 )
500 {
501     RS_RES_ALLOC_PARAMS_INTERNAL params;
502     CALL_CONTEXT  callContext;
503     CALL_CONTEXT *pOldContext = NULL;
504 
505     RsClient *pClientDst = NULL;
506     RsResourceRef *pParentRef = NULL;
507 
508     NV_STATUS status;
509 
510     status = serverGetClientUnderLock(pServer, pParams->hClientDst, &pClientDst);
511     if (status != NV_OK)
512         return status;
513 
514     status = clientGetResourceRef(pClientDst, pParams->hParentDst, &pParentRef);
515     if (status != NV_OK)
516         return status;
517 
518     portMemSet(&callContext, 0, sizeof(callContext));
519     callContext.pServer = pServer;
520     callContext.pClient = pClient;
521     callContext.pResourceRef = pParams->pSrcRef;
522     callContext.pContextRef = pParentRef;
523     callContext.secInfo = *pParams->pSecInfo;
524     callContext.pLockInfo = pParams->pLockInfo;
525 
526     NV_ASSERT_OK_OR_RETURN(resservSwapTlsCallContext(&pOldContext, &callContext));
527 
528     //
529     // Kernel clients are allowed to dup anything, unless they request otherwise.
530     // Also, if access rights are disabled, owner client should still be able to dup.
531     // For anything else, check that the client has dup access on the object
532     //
533     if (((pParams->pSecInfo->privLevel < RS_PRIV_LEVEL_KERNEL) ||
534          (pParams->flags & NV04_DUP_HANDLE_FLAGS_REJECT_KERNEL_DUP_PRIVILEGE)) &&
535         (pServer->bRsAccessEnabled || (pParams->pSrcClient->hClient != pClient->hClient)))
536     {
537         RS_ACCESS_MASK rightsRequired;
538 
539         portMemSet(&rightsRequired, 0, sizeof(rightsRequired));
540         RS_ACCESS_MASK_ADD(&rightsRequired, RS_ACCESS_DUP_OBJECT);
541 
542         status = rsAccessCheckRights(pParams->pSrcRef, pClient, &rightsRequired);
543     }
544     else
545     {
546         // Server's globalInternalSharePolicyList applies Require policies even to kernel
547         RsShareListIter it = listIterAll(&pServer->globalInternalSharePolicyList);
548         while (listIterNext(&it))
549         {
550             RS_SHARE_POLICY *pSharePolicy = it.pValue;
551 
552             // We only care about failing Require policies which apply to Dup, ignore everything else
553             if ((pSharePolicy->action & RS_SHARE_ACTION_FLAG_REQUIRE) &&
554                 RS_ACCESS_MASK_TEST(&pSharePolicy->accessMask, RS_ACCESS_DUP_OBJECT) &&
555                 !resShareCallback(pParams->pSrcRef->pResource, pClient, pParentRef, pSharePolicy))
556             {
557                 status = NV_ERR_INVALID_REQUEST;
558                 break;
559             }
560         }
561     }
562 
563     NV_ASSERT_OK(resservRestoreTlsCallContext(pOldContext));
564 
565     if (status != NV_OK)
566         return status;
567 
568     portMemSet(&params, 0, sizeof(params));
569 
570     params.hClient = pClient->hClient;
571     params.hParent = pParams->hParentDst;
572     params.hResource = pParams->hResourceDst;
573     params.externalClassId = pParams->pSrcRef->externalClassId;
574     params.pSecInfo = pParams->pSecInfo;
575 
576     params.pSrcClient = pParams->pSrcClient;
577     params.pSrcRef = pParams->pSrcRef;
578     params.pAllocParams = pParams->pShareParams;
579     params.pLockInfo = pParams->pLockInfo;
580     params.allocFlags = pParams->flags;
581 
582     return _clientAllocResourceHelper(pClient, pServer, &params, &pParams->hResourceDst);
583 }
584 
585 static
586 void
_refCleanupDependencies(RsResourceRef * pResourceRef)587 _refCleanupDependencies
588 (
589     RsResourceRef *pResourceRef
590 )
591 {
592     RsResourceRef **ppIndepRef;
593     while (NULL != (ppIndepRef = multimapFirstItem(&pResourceRef->depBackRefMap)))
594     {
595         refRemoveDependant(*ppIndepRef, pResourceRef);
596     }
597 }
598 
599 static
600 void
_refCleanupDependants(RsResourceRef * pResourceRef)601 _refCleanupDependants
602 (
603     RsResourceRef *pResourceRef
604 )
605 {
606     RsResourceRef **ppDepRef;
607     while (NULL != (ppDepRef = multimapFirstItem(&pResourceRef->depRefMap)))
608     {
609         refRemoveDependant(pResourceRef, *ppDepRef);
610     }
611 }
612 
613 static
614 void
_refRemoveAllDependencies(RsResourceRef * pResourceRef)615 _refRemoveAllDependencies
616 (
617     RsResourceRef *pResourceRef
618 )
619 {
620     _refCleanupDependencies(pResourceRef);
621 
622     if (pResourceRef->pDependantSession != NULL)
623         sessionRemoveDependency(pResourceRef->pDependantSession, pResourceRef);
624 
625     if (pResourceRef->pSession != NULL)
626         sessionRemoveDependant(pResourceRef->pSession, pResourceRef);
627 }
628 
629 static
630 NV_STATUS
_clientAllocResourceHelper(RsClient * pClient,RsServer * pServer,RS_RES_ALLOC_PARAMS_INTERNAL * pParams,NvHandle * phResource)631 _clientAllocResourceHelper
632 (
633     RsClient *pClient,
634     RsServer *pServer,
635     RS_RES_ALLOC_PARAMS_INTERNAL *pParams,
636     NvHandle *phResource
637 )
638 {
639     NV_STATUS       status;
640     NvHandle        hResource = *phResource;
641     NvU32           depth = 0;
642     RsResource     *pResource = NULL;
643     RsResourceRef  *pParentRef = NULL;
644     RsResourceRef  *pResourceRef = NULL;
645     CALL_CONTEXT    callContext;
646     CALL_CONTEXT   *pOldContext = NULL;
647     NvHandle        hParent = pParams->hParent;
648 
649     status = clientGetResourceRef(pClient, hParent, &pParentRef);
650     if (status != NV_OK && hParent != pClient->hClient && hParent != 0)
651         return status;
652 
653     status = _clientConstructResourceRef(pClient, pServer, pParentRef, hResource, pParams->externalClassId, &pResourceRef);
654     if (status != NV_OK)
655         goto fail;
656 
657     portMemSet(&callContext, 0, sizeof(callContext));
658     callContext.pServer = pServer;
659     callContext.pClient = pClient;
660     callContext.pResourceRef = pResourceRef;
661     callContext.pContextRef = pParams->pSrcRef;
662     callContext.pLockInfo = pParams->pLockInfo;
663 
664     if (pParams->pSecInfo == NULL)
665     {
666         status = NV_ERR_INVALID_ARGUMENT;
667         goto fail;
668     }
669     callContext.secInfo = *pParams->pSecInfo;
670 
671     NV_ASSERT_OK_OR_GOTO(status,
672         resservSwapTlsCallContext(&pOldContext, &callContext), fail);
673 
674     status = resservResourceFactory(pServer->pAllocator, &callContext, pParams, &pResource);
675     NV_ASSERT_OK(resservRestoreTlsCallContext(pOldContext));
676 
677     if (status != NV_OK)
678         goto fail;
679 
680     // Clear free params implicitly set by constructor
681     resSetFreeParams(pResource, NULL, NULL);
682     pParams->pResourceRef = pResourceRef;
683 
684     //
685     // resConstruct_IMPL sets these fields but we need to set them again until
686     // Bug 2527351 is fixed
687     //
688     pResourceRef->pResource = pResource;
689     pResource->pResourceRef = pResourceRef;
690 
691     if (pParentRef != NULL)
692     {
693         depth = pParentRef->depth + 1;
694         pResourceRef->depth = depth;
695 
696         // Allow one additional level of depth to offset the depth used up by the RsClientResource at the root
697         // of the object hierarchy
698         if (RS_MAX_RESOURCE_DEPTH + 1 <= depth)
699         {
700             status = NV_ERR_ILLEGAL_ACTION;
701             goto fail;
702         }
703 
704         // Add this ref to the parent's child map
705         if (NV_OK != indexAdd(&pParentRef->childRefMap, pResourceRef->internalClassId, pResourceRef))
706         {
707             status = NV_ERR_INSUFFICIENT_RESOURCES;
708             goto fail;
709         }
710     }
711 
712     if (pServer->bRsAccessEnabled)
713     {
714         status = rsAccessGrantRights(pResourceRef, &callContext, pClient,
715                                      pParams->pRightsRequested,
716                                      pParams->pRightsRequired,
717                                      pParams->pAllocParams);
718         if (status != NV_OK)
719             goto fail;
720     }
721 
722     *phResource = hResource;
723 
724     return NV_OK;
725 
726 fail:
727     if (pResource != NULL)
728     {
729         NV_STATUS callContextStatus;
730 
731         RS_RES_FREE_PARAMS_INTERNAL params;
732         pOldContext = NULL;
733 
734         // First undo dependency tracking since it might access the resource
735         _refRemoveAllDependencies(pResourceRef);
736 
737         portMemSet(&params, 0, sizeof(params));
738         portMemSet(&callContext, 0, sizeof(callContext));
739         callContext.pServer = pServer;
740         callContext.pClient = pClient;
741         callContext.secInfo = *pParams->pSecInfo;
742         callContext.pResourceRef = pResourceRef;
743         callContext.pLockInfo = pParams->pLockInfo;
744 
745         callContextStatus = resservSwapTlsCallContext(&pOldContext, &callContext);
746         if (callContextStatus == NV_OK)
747         {
748             resSetFreeParams(pResource, &callContext, &params);
749 
750             objDelete(pResource);
751             NV_ASSERT_OK(resservRestoreTlsCallContext(pOldContext));
752         }
753         else
754         {
755             NV_PRINTF(LEVEL_ERROR, "Failed to set call context! Error: 0x%x\n",
756                 callContextStatus);
757         }
758 
759     }
760 
761     if (pResourceRef != NULL)
762     {
763         if (pParentRef != NULL)
764         {
765             indexRemove(&pParentRef->childRefMap, pResourceRef->internalClassId, pResourceRef);
766         }
767 
768         clientDestructResourceRef(pClient, pServer, pResourceRef);
769     }
770 
771     return status;
772 }
773 
774 NV_STATUS
clientFreeResource_IMPL(RsClient * pClient,RsServer * pServer,RS_RES_FREE_PARAMS_INTERNAL * pParams)775 clientFreeResource_IMPL
776 (
777     RsClient   *pClient,
778     RsServer   *pServer,
779     RS_RES_FREE_PARAMS_INTERNAL *pParams
780 )
781 {
782     NV_STATUS       status = NV_OK;
783     NV_STATUS       tmpStatus;
784     CALL_CONTEXT    callContext;
785     CALL_CONTEXT   *pOldContext = NULL;
786     RsResourceRef  *pClientRef = NULL;
787     RsResourceRef  *pParentRef = NULL;
788     RsResourceRef  *pResourceRef;
789     RsResource     *pResource;
790 
791     pResourceRef = mapFind(&pClient->resourceMap, pParams->hResource);
792     if (pResourceRef == NULL)
793         return NV_ERR_OBJECT_NOT_FOUND;
794 
795     if (refPendingFree(pResourceRef, pClient))
796         listRemove(&pClient->pendingFreeList, pResourceRef);
797 
798     pResource = pResourceRef->pResource;
799     pParentRef = pResourceRef->pParentRef;
800 
801     if (pResourceRef->bInvalidated)
802         goto done;
803 
804     portMemSet(&callContext, 0, sizeof(callContext));
805     callContext.pClient = pClient;
806     callContext.pResourceRef = pResourceRef;
807     callContext.pServer = pServer;
808     callContext.pLockInfo = pParams->pLockInfo;
809 
810     // Some MODS tests don't set secInfo.
811     if (pParams->pSecInfo != NULL)
812         callContext.secInfo = *pParams->pSecInfo;
813 
814     NV_ASSERT_OK_OR_GOTO(status,
815         resservSwapTlsCallContext(&pOldContext, &callContext), done);
816 
817     resSetFreeParams(pResource, &callContext, pParams);
818 
819     resPreDestruct(pResource);
820 
821     // Remove all CPU mappings
822     clientUnmapResourceRefMappings(pClient, &callContext, pParams->pLockInfo);
823     _clientUnmapBackRefMappings(pClient, &callContext, pParams->pLockInfo);
824 
825     // Remove all inter-mappings
826     _clientUnmapInterMappings(pClient, &callContext, pParams->pLockInfo);
827     _clientUnmapInterBackRefMappings(pClient, &callContext, pParams->pLockInfo);
828 
829     // Remove this resource as a dependency from other resources
830     pResourceRef->bInvalidated = NV_TRUE;
831     _refRemoveAllDependencies(pResourceRef);
832 
833     status = serverFreeResourceRpcUnderLock(pServer, pParams);
834     NV_ASSERT(status == NV_OK);
835 
836     // NV_PRINTF(LEVEL_INFO, "hClient %x: Freeing hResource: %x\n",
837     //          pClient->hClient, pResourceRef->hResource);
838 
839     objDelete(pResource);
840 
841     pResourceRef->pResource = NULL;
842 
843     NV_ASSERT_OK(resservRestoreTlsCallContext(pOldContext));
844 
845 done:
846     if (!pParams->bInvalidateOnly)
847     {
848         // Remove this ref from its parent's child ref list
849         if (pParentRef != NULL)
850         {
851             multimapRemoveItemByKey(&pParentRef->childRefMap,
852                 pResourceRef->internalClassId, pResourceRef->hResource);
853         }
854 
855         pClientRef = mapFind(&pClient->resourceMap, pClient->hClient);
856         if (pClientRef != NULL)
857             refUncacheRef(pClientRef, pResourceRef);
858 
859         tmpStatus = clientDestructResourceRef(pClient, pServer, pResourceRef);
860         NV_ASSERT(tmpStatus == NV_OK);
861     }
862 
863     return status;
864 }
865 
866 NV_STATUS
clientUnmapMemory_IMPL(RsClient * pClient,RsResourceRef * pResourceRef,RS_LOCK_INFO * pLockInfo,RsCpuMapping ** ppCpuMapping,API_SECURITY_INFO * pSecInfo)867 clientUnmapMemory_IMPL
868 (
869     RsClient *pClient,
870     RsResourceRef *pResourceRef,
871     RS_LOCK_INFO  *pLockInfo,
872     RsCpuMapping **ppCpuMapping,
873     API_SECURITY_INFO *pSecInfo
874 )
875 {
876     NV_STATUS status;
877     CALL_CONTEXT callContext;
878     CALL_CONTEXT *pOldContext = NULL;
879     RsCpuMapping *pCpuMapping = *ppCpuMapping;
880 
881     portMemSet(&callContext, 0, sizeof(callContext));
882     callContext.pClient = pClient;
883     callContext.pResourceRef = pResourceRef;
884     callContext.pLockInfo = pLockInfo;
885 
886     // Some MODS tests don't set secInfo.
887     if (pSecInfo != NULL)
888         callContext.secInfo = *pSecInfo;
889 
890     NV_ASSERT_OK_OR_RETURN(resservSwapTlsCallContext(&pOldContext, &callContext));
891 
892     status = resUnmap(pResourceRef->pResource, &callContext, pCpuMapping);
893     NV_ASSERT_OK(resservRestoreTlsCallContext(pOldContext));
894 
895     if (status != NV_OK)
896     {
897         NV_PRINTF(LEVEL_ERROR, "hClient %x: Failed to unmap cpu mapping: hResource: %x error: 0x%x\n",
898                 pClient->hClient,
899                 pResourceRef->hResource,
900                 status);
901 
902         if (pCpuMapping != NULL)
903         {
904             NV_PRINTF(LEVEL_ERROR, "hContext: %x\n",
905                       (pCpuMapping->pContextRef == NULL) ? 0 : pCpuMapping->pContextRef->hResource);
906         }
907     }
908 
909     refRemoveMapping(pResourceRef, pCpuMapping);
910     *ppCpuMapping = NULL;
911 
912     return status;
913 }
914 
915 NV_STATUS
clientInterMap_IMPL(RsClient * pClient,RsResourceRef * pMapperRef,RsResourceRef * pMappableRef,RS_INTER_MAP_PARAMS * pParams)916 clientInterMap_IMPL
917 (
918     RsClient *pClient,
919     RsResourceRef *pMapperRef,
920     RsResourceRef *pMappableRef,
921     RS_INTER_MAP_PARAMS *pParams
922 )
923 {
924     return NV_ERR_INVALID_CLIENT;
925 }
926 
927 NV_STATUS
clientInterUnmap_IMPL(RsClient * pClient,RsResourceRef * pMapperRef,RS_INTER_UNMAP_PARAMS * pParams)928 clientInterUnmap_IMPL
929 (
930     RsClient *pClient,
931     RsResourceRef *pMapperRef,
932     RS_INTER_UNMAP_PARAMS *pParams
933 )
934 {
935     return NV_ERR_INVALID_CLIENT;
936 }
937 
938 NV_STATUS
clientGenResourceHandle_IMPL(RsClient * pClient,NvHandle * pHandle)939 clientGenResourceHandle_IMPL
940 (
941     RsClient *pClient,
942     NvHandle *pHandle
943 )
944 {
945     NvHandle hFirst;
946     NvHandle hResource;
947     NV_STATUS status;
948 
949     NV_ASSERT(pClient->handleRangeStart != 0);
950     NV_ASSERT(pClient->handleRangeSize != 0);
951 
952     hResource = pClient->handleRangeStart + ((pClient->handleGenIdx++) % pClient->handleRangeSize);
953     status = clientValidateNewResourceHandle(pClient, hResource, NV_FALSE);
954     if (status == NV_OK)
955     {
956         goto done;
957     }
958 
959     hFirst = hResource;
960     do
961     {
962         hResource = pClient->handleRangeStart + ((pClient->handleGenIdx++) % pClient->handleRangeSize);
963         status = clientValidateNewResourceHandle(pClient, hResource, NV_FALSE);
964     } while(hResource != hFirst && status != NV_OK);
965 
966     if (status != NV_OK)
967         return NV_ERR_INSUFFICIENT_RESOURCES;
968 
969 done:
970     NV_ASSERT(hResource - pClient->handleRangeStart < pClient->handleRangeSize);
971 
972     *pHandle = hResource;
973     return NV_OK;
974 }
975 
976 NV_STATUS
clientAssignResourceHandle_IMPL(RsClient * pClient,NvHandle * phResource)977 clientAssignResourceHandle_IMPL
978 (
979     RsClient *pClient,
980     NvHandle *phResource
981 )
982 {
983     NV_STATUS status;
984 
985     if (phResource == NULL)
986         return NV_ERR_INVALID_ARGUMENT;
987 
988     if (*phResource == 0)
989     {
990         status = clientGenResourceHandle(pClient, phResource);
991     }
992     else
993     {
994         status = clientValidateNewResourceHandle(pClient, *phResource, NV_TRUE);
995     }
996 
997     return status;
998 
999 }
1000 
1001 static
1002 NV_STATUS
_clientConstructResourceRef(RsClient * pClient,RsServer * pServer,RsResourceRef * pParentRef,NvHandle hResource,NvU32 externalClassId,RsResourceRef ** ppResourceRef)1003 _clientConstructResourceRef
1004 (
1005     RsClient *pClient,
1006     RsServer *pServer,
1007     RsResourceRef *pParentRef,
1008     NvHandle hResource,
1009     NvU32    externalClassId,
1010     RsResourceRef **ppResourceRef
1011 )
1012 {
1013     PORT_MEM_ALLOCATOR *pAllocator = pServer->pAllocator;
1014     RsResourceRef *pResourceRef = mapInsertNew(&pClient->resourceMap, hResource);
1015     if (pResourceRef == NULL)
1016         return NV_ERR_INSUFFICIENT_RESOURCES;
1017 
1018     if (!pClient->bResourceWarning && (mapCount(&pClient->resourceMap) >= RS_CLIENT_RESOURCE_WARNING_THRESHOLD))
1019     {
1020         NV_PRINTF(LEVEL_WARNING, "Client 0x%08x has allocated a large number of resources. [Current classid: 0x%04x]\n", pClient->hClient, externalClassId);
1021         NV_PRINTF(LEVEL_WARNING, "The client may be leaking resources. This warning can be ignored if the allocations were intentional.\n");
1022         pClient->bResourceWarning = NV_TRUE;
1023     }
1024 
1025     pResourceRef->pClient = pClient;
1026     pResourceRef->pResourceDesc = RsResInfoByExternalClassId(externalClassId);
1027     pResourceRef->externalClassId = externalClassId;
1028     pResourceRef->internalClassId = RsResInfoGetInternalClassId(pResourceRef->pResourceDesc);
1029     pResourceRef->pResource = NULL;
1030     pResourceRef->pParentRef = pParentRef;
1031     pResourceRef->hResource = hResource;
1032     pResourceRef->depth = 0;
1033 
1034     multimapInit(&pResourceRef->childRefMap, pAllocator);
1035     multimapInit(&pResourceRef->cachedRefMap, pAllocator);
1036     multimapInit(&pResourceRef->depRefMap, pAllocator);
1037     multimapInit(&pResourceRef->depBackRefMap, pAllocator);
1038     listInit(&pResourceRef->cpuMappings, pAllocator);
1039     listInit(&pResourceRef->backRefs, pAllocator);
1040     listInit(&pResourceRef->interMappings, pAllocator);
1041     listInit(&pResourceRef->interBackRefs, pAllocator);
1042     listInit(&pResourceRef->sharePolicyList, pAllocator);
1043 
1044     portAtomicExIncrementU64(&pServer->activeResourceCount);
1045 
1046     *ppResourceRef = pResourceRef;
1047     return NV_OK;
1048 }
1049 
1050 NV_STATUS
clientDestructResourceRef_IMPL(RsClient * pClient,RsServer * pServer,RsResourceRef * pResourceRef)1051 clientDestructResourceRef_IMPL
1052 (
1053     RsClient *pClient,
1054     RsServer *pServer,
1055     RsResourceRef *pResourceRef
1056 )
1057 {
1058     NV_ASSERT(pResourceRef != NULL);
1059     NV_ASSERT(listCount(&pResourceRef->backRefs) == 0);
1060     NV_ASSERT(listCount(&pResourceRef->cpuMappings) == 0);
1061     NV_ASSERT(listCount(&pResourceRef->interBackRefs) == 0);
1062     NV_ASSERT(listCount(&pResourceRef->interMappings) == 0);
1063 
1064     listDestroy(&pResourceRef->backRefs);
1065     listDestroy(&pResourceRef->cpuMappings);
1066     listDestroy(&pResourceRef->interBackRefs);
1067     listDestroy(&pResourceRef->interMappings);
1068     listDestroy(&pResourceRef->sharePolicyList);
1069 
1070     // All children should be free
1071     NV_ASSERT(0 == multimapCountItems(&pResourceRef->childRefMap));
1072     multimapDestroy(&pResourceRef->childRefMap);
1073 
1074     // Nothing should be cached
1075     NV_ASSERT(0 == multimapCountItems(&pResourceRef->cachedRefMap));
1076     multimapDestroy(&pResourceRef->cachedRefMap);
1077 
1078     _refCleanupDependencies(pResourceRef);
1079     multimapDestroy(&pResourceRef->depBackRefMap);
1080 
1081     _refCleanupDependants(pResourceRef);
1082     multimapDestroy(&pResourceRef->depRefMap);
1083 
1084     mapRemove(&pClient->resourceMap, pResourceRef);
1085 
1086     portAtomicExDecrementU64(&pServer->activeResourceCount);
1087 
1088     return NV_OK;
1089 }
1090 
1091 NV_STATUS
clientUnmapResourceRefMappings(RsClient * pClient,CALL_CONTEXT * pCallContext,RS_LOCK_INFO * pLockInfo)1092 clientUnmapResourceRefMappings
1093 (
1094     RsClient *pClient,
1095     CALL_CONTEXT *pCallContext,
1096     RS_LOCK_INFO *pLockInfo
1097 )
1098 {
1099     RsResourceRef  *pResourceRef = pCallContext->pResourceRef;
1100     RsCpuMapping   *pCpuMapping;
1101     NV_STATUS status;
1102     RS_LOCK_INFO lockInfo;
1103     RS_CPU_UNMAP_PARAMS params;
1104 
1105     pCpuMapping = listHead(&pResourceRef->cpuMappings);
1106     while(pCpuMapping != NULL)
1107     {
1108         portMemSet(&params, 0, sizeof(params));
1109         portMemSet(&lockInfo, 0, sizeof(lockInfo));
1110 
1111         params.hClient = pClient->hClient;
1112         params.hDevice = (pCpuMapping->pContextRef == NULL)
1113             ? pClient->hClient
1114             : pCpuMapping->pContextRef->hResource;
1115         params.hMemory = pResourceRef->hResource;
1116         params.pLinearAddress = pCpuMapping->pLinearAddress;
1117         params.processId = pCpuMapping->processId;
1118         params.bTeardown = NV_TRUE;
1119         params.flags = pCpuMapping->flags;
1120         params.pSecInfo = &pCallContext->secInfo;
1121         params.pLockInfo = &lockInfo;
1122         lockInfo.pClient = pLockInfo->pClient;
1123         lockInfo.state = pLockInfo->state;
1124 
1125         // TODO: temp WAR for bug 2840284: deadlock during recursive free operation
1126         lockInfo.flags |= RS_LOCK_FLAGS_NO_CLIENT_LOCK;
1127 
1128         status = serverUnmap(pCallContext->pServer, params.hClient, params.hMemory, &params);
1129 
1130         if (status != NV_OK)
1131         {
1132             NV_PRINTF(LEVEL_ERROR, "Failed to auto-unmap (status=0x%x) hClient %x: hResource: %x\n",
1133                     status, pClient->hClient, pResourceRef->hResource);
1134             NV_PRINTF(LEVEL_ERROR, "hContext: %x at addr " NvP64_fmt "\n",
1135                     params.hDevice, params.pLinearAddress);
1136 
1137             if (pCpuMapping == listHead(&pResourceRef->cpuMappings))
1138             {
1139 #if !(RS_STANDALONE_TEST)
1140                 NV_ASSERT(0);
1141 #endif
1142                 refRemoveMapping(pResourceRef, pCpuMapping);
1143             }
1144         }
1145         pCpuMapping = listHead(&pResourceRef->cpuMappings);
1146     }
1147 
1148     return NV_OK;
1149 }
1150 
1151 NV_STATUS
_clientUnmapBackRefMappings(RsClient * pClient,CALL_CONTEXT * pCallContext,RS_LOCK_INFO * pLockInfo)1152 _clientUnmapBackRefMappings
1153 (
1154     RsClient *pClient,
1155     CALL_CONTEXT *pCallContext,
1156     RS_LOCK_INFO *pLockInfo
1157 )
1158 {
1159     NV_STATUS       status;
1160     RsResourceRef  *pResourceRef = pCallContext->pResourceRef;
1161     RS_CPU_MAPPING_BACK_REF *pBackRefItem;
1162     RS_LOCK_INFO lockInfo;
1163     RS_CPU_UNMAP_PARAMS params;
1164 
1165     pBackRefItem = listHead(&pResourceRef->backRefs);
1166     while(pBackRefItem != NULL)
1167     {
1168         RsCpuMapping *pCpuMapping = pBackRefItem->pCpuMapping;
1169         RsResourceRef *pBackRef = pBackRefItem->pBackRef;
1170 
1171         portMemSet(&params, 0, sizeof(params));
1172         portMemSet(&lockInfo, 0, sizeof(lockInfo));
1173 
1174         params.hClient = pClient->hClient;
1175         params.hDevice = (pCpuMapping->pContextRef == NULL)
1176             ? pClient->hClient
1177             : pCpuMapping->pContextRef->hResource;
1178         params.hMemory = pBackRef->hResource;
1179         params.pLinearAddress = pCpuMapping->pLinearAddress;
1180         params.processId = pCpuMapping->processId;
1181         params.bTeardown = NV_TRUE;
1182         params.flags = pCpuMapping->flags;
1183         params.pSecInfo = &pCallContext->secInfo;
1184         params.pLockInfo = &lockInfo;
1185 
1186         lockInfo.pClient = pLockInfo->pClient;
1187         lockInfo.state = pLockInfo->state;
1188 
1189         status = serverUnmap(pCallContext->pServer, pClient->hClient, pBackRef->hResource, &params);
1190         if (status != NV_OK)
1191         {
1192             NV_PRINTF(LEVEL_ERROR, "Failed to auto-unmap backref (status=0x%x) hClient %x: hResource: %x\n",
1193                     status, pClient->hClient, pBackRef->hResource);
1194             NV_PRINTF(LEVEL_ERROR, "hContext: %x at addr " NvP64_fmt "\n",
1195                     params.hDevice, params.pLinearAddress);
1196 
1197             if (pBackRefItem == listHead(&pResourceRef->backRefs))
1198             {
1199                 NV_ASSERT(0);
1200                 listRemove(&pResourceRef->backRefs, pBackRefItem);
1201             }
1202         }
1203 
1204         pBackRefItem = listHead(&pResourceRef->backRefs);
1205     }
1206 
1207     return NV_OK;
1208 }
1209 
1210 static NV_STATUS
_unmapInterMapping(RsServer * pServer,RsClient * pClient,RsResourceRef * pMapperRef,RsInterMapping * pMapping,RS_LOCK_INFO * pLockInfo,API_SECURITY_INFO * pSecInfo)1211 _unmapInterMapping
1212 (
1213     RsServer *pServer,
1214     RsClient *pClient,
1215     RsResourceRef *pMapperRef,
1216     RsInterMapping *pMapping,
1217     RS_LOCK_INFO *pLockInfo,
1218     API_SECURITY_INFO *pSecInfo
1219 )
1220 {
1221     RS_INTER_UNMAP_PARAMS params;
1222     RS_LOCK_INFO lockInfo;
1223     NV_STATUS status;
1224 
1225     portMemSet(&params, 0, sizeof(params));
1226     portMemSet(&lockInfo, 0, sizeof(lockInfo));
1227 
1228     params.hClient = pClient->hClient;
1229     params.hMapper = pMapperRef->hResource;
1230     params.hDevice = pMapping->pContextRef->hResource;
1231     params.flags = pMapping->flags;
1232     params.dmaOffset = pMapping->dmaOffset;
1233     params.size = 0;
1234     params.pMemDesc = pMapping->pMemDesc;
1235     params.pSecInfo = pSecInfo;
1236     params.pLockInfo = &lockInfo;
1237 
1238     lockInfo.pClient = pLockInfo->pClient;
1239     lockInfo.pContextRef = (pLockInfo->pContextRef != NULL)
1240         ? pLockInfo->pContextRef
1241         : pMapping->pContextRef;
1242     lockInfo.state = pLockInfo->state;
1243 
1244     status = serverUpdateLockFlagsForInterAutoUnmap(pServer, &params);
1245     if (status != NV_OK)
1246         return status;
1247 
1248     return serverInterUnmap(pServer, &params);
1249 }
1250 
1251 void
_clientUnmapInterMappings(RsClient * pClient,CALL_CONTEXT * pCallContext,RS_LOCK_INFO * pLockInfo)1252 _clientUnmapInterMappings
1253 (
1254     RsClient *pClient,
1255     CALL_CONTEXT *pCallContext,
1256     RS_LOCK_INFO *pLockInfo
1257 )
1258 {
1259     NV_STATUS status;
1260     RsResourceRef *pMapperRef = pCallContext->pResourceRef;
1261     RsInterMapping *pMapping;
1262 
1263     pMapping = listHead(&pMapperRef->interMappings);
1264     while (pMapping != NULL)
1265     {
1266         status = _unmapInterMapping(pCallContext->pServer, pClient, pMapperRef,
1267                                     pMapping, pLockInfo, &pCallContext->secInfo);
1268         if (status != NV_OK)
1269         {
1270             NV_PRINTF(LEVEL_ERROR, "Failed to auto-unmap (status=0x%x) hClient %x: hMapper: %x\n",
1271                       status, pClient->hClient, pMapperRef->hResource);
1272             NV_PRINTF(LEVEL_ERROR, "hMappable: %x hContext: %x\n",
1273                       pMapping->pMappableRef->hResource, pMapping->pContextRef->hResource);
1274 
1275             if (pMapping == listHead(&pMapperRef->interMappings))
1276             {
1277                 NV_ASSERT(0);
1278                 refRemoveInterMapping(pMapperRef, pMapping);
1279             }
1280         }
1281 
1282         pMapping = listHead(&pMapperRef->interMappings);
1283     }
1284 }
1285 
1286 void
_clientUnmapInterBackRefMappings(RsClient * pClient,CALL_CONTEXT * pCallContext,RS_LOCK_INFO * pLockInfo)1287 _clientUnmapInterBackRefMappings
1288 (
1289     RsClient *pClient,
1290     CALL_CONTEXT *pCallContext,
1291     RS_LOCK_INFO *pLockInfo
1292 )
1293 {
1294     NV_STATUS status;
1295     RS_INTER_MAPPING_BACK_REF *pBackRefItem;
1296 
1297     RsResourceRef *pResourceRef = pCallContext->pResourceRef;
1298 
1299     pBackRefItem = listHead(&pResourceRef->interBackRefs);
1300     while (pBackRefItem != NULL)
1301     {
1302         RsResourceRef *pMapperRef = pBackRefItem->pMapperRef;
1303         RsInterMapping *pMapping = pBackRefItem->pMapping;
1304 
1305         status = _unmapInterMapping(pCallContext->pServer, pClient, pMapperRef,
1306                                     pMapping, pLockInfo, &pCallContext->secInfo);
1307         if (status != NV_OK)
1308         {
1309             NV_PRINTF(LEVEL_ERROR, "Failed to auto-unmap backref (status=0x%x) hClient %x: hMapper: %x\n",
1310                       status, pClient->hClient, pMapperRef->hResource);
1311             NV_PRINTF(LEVEL_ERROR, "hMappable: %x hContext: %x\n",
1312                       pMapping->pMappableRef->hResource, pMapping->pContextRef->hResource);
1313 
1314             if (pBackRefItem == listHead(&pResourceRef->interBackRefs))
1315             {
1316                 NV_ASSERT(0);
1317                 refRemoveInterMapping(pMapperRef, pMapping);
1318             }
1319         }
1320 
1321         pBackRefItem = listHead(&pResourceRef->interBackRefs);
1322     }
1323 }
1324 
1325 NV_STATUS
indexAdd(RsIndex * pIndex,NvU32 index,RsResourceRef * pResourceRef)1326 indexAdd
1327 (
1328     RsIndex *pIndex,
1329     NvU32 index,
1330     RsResourceRef *pResourceRef
1331 )
1332 {
1333     NV_ASSERT(pResourceRef != NULL && pResourceRef->hResource != 0);
1334 
1335     if (NULL == multimapFindSubmap(pIndex, index))
1336     {
1337         if (NULL == multimapInsertSubmap(pIndex, index))
1338             return NV_ERR_INSUFFICIENT_RESOURCES;
1339     }
1340 
1341     if (NULL == multimapInsertItemValue(pIndex, index, pResourceRef->hResource,
1342                                         &pResourceRef))
1343         return NV_ERR_INSUFFICIENT_RESOURCES;
1344 
1345     return NV_OK;
1346 }
1347 
1348 NV_STATUS
indexRemove(RsIndex * pIndex,NvU32 index,RsResourceRef * pResourceRef)1349 indexRemove
1350 (
1351     RsIndex *pIndex,
1352     NvU32 index,
1353     RsResourceRef *pResourceRef
1354 )
1355 {
1356     RsResourceRef **ppResourceRef;
1357 
1358     NV_ASSERT(pResourceRef != NULL && pResourceRef->hResource != 0);
1359 
1360     ppResourceRef = multimapFindItem(pIndex, index, pResourceRef->hResource);
1361     if (ppResourceRef == NULL)
1362         return NV_ERR_OBJECT_NOT_FOUND;
1363 
1364     multimapRemoveItem(pIndex, ppResourceRef);
1365 
1366     return NV_OK;
1367 }
1368 
1369 NV_STATUS
clientValidateNewResourceHandle_IMPL(RsClient * pClient,NvHandle hResource,NvBool bRestrict)1370 clientValidateNewResourceHandle_IMPL
1371 (
1372     RsClient *pClient,
1373     NvHandle  hResource,
1374     NvBool    bRestrict
1375 )
1376 {
1377     //
1378     // Resource handle should not be the same as the client handle
1379     // because some control calls pass hClient in the hObject field
1380     //
1381     if (pClient->hClient == hResource || hResource == 0)
1382         return NV_ERR_INVALID_OBJECT_HANDLE;
1383 
1384     if (bRestrict && !rangeIsEmpty(pClient->handleRestrictRange))
1385     {
1386         NV_RANGE requestedRange = rangeMake(hResource, hResource);
1387         if (rangeContains(pClient->handleRestrictRange, requestedRange))
1388             return NV_ERR_INVALID_OBJECT_HANDLE;
1389     }
1390 
1391     if (clientGetResourceRef(pClient, hResource, NULL) == NV_OK)
1392         return NV_ERR_INSERT_DUPLICATE_NAME;
1393 
1394     return NV_OK;
1395 }
1396 
1397 NV_STATUS
clientresConstruct_IMPL(RsClientResource * pClientRes,CALL_CONTEXT * pCallContext,RS_RES_ALLOC_PARAMS_INTERNAL * pParams)1398 clientresConstruct_IMPL
1399 (
1400     RsClientResource *pClientRes,
1401     CALL_CONTEXT *pCallContext,
1402     RS_RES_ALLOC_PARAMS_INTERNAL *pParams
1403 )
1404 {
1405     RsClient *pClient = pCallContext->pClient;
1406     RsResourceRef *pResourceRef = pCallContext->pResourceRef;
1407 
1408     // Client proxy resource must have the same handle as its client
1409     if (pClient->hClient != pResourceRef->hResource)
1410         return NV_ERR_INVALID_OBJECT_HANDLE;
1411 
1412     pClientRes->pClient = pCallContext->pClient;
1413     return NV_OK;
1414 }
1415 
1416 void
clientresDestruct_IMPL(RsClientResource * pClientRes)1417 clientresDestruct_IMPL
1418 (
1419     RsClientResource *pClientRes
1420 )
1421 {
1422 }
1423 
1424 RsIndexIter
indexRefIter(RsIndex * pIndex,NvU32 index)1425 indexRefIter
1426 (
1427     RsIndex *pIndex,
1428     NvU32 index
1429 )
1430 {
1431     RsIndexIter it;
1432     RsIndexSubmap *pSubmap;
1433 
1434     portMemSet(&it, 0, sizeof(it));
1435     NV_ASSERT(pIndex);
1436 
1437     pSubmap = multimapFindSubmap(pIndex, index);
1438     if (pSubmap != NULL)
1439         it = multimapSubmapIterItems(pIndex, pSubmap);
1440 
1441     return it;
1442 }
1443 
1444 RsIndexIter
indexRefIterAll(RsIndex * pIndex)1445 indexRefIterAll
1446 (
1447     RsIndex *pIndex
1448 )
1449 {
1450     NV_ASSERT(pIndex);
1451     return multimapItemIterAll(pIndex);
1452 }
1453 
1454 NvBool
indexRefIterNext(RsIndexIter * pIt)1455 indexRefIterNext
1456 (
1457     RsIndexIter *pIt
1458 )
1459 {
1460     return multimapItemIterNext(pIt);
1461 }
1462 
1463 RS_ITERATOR
clientRefIter(RsClient * pClient,RsResourceRef * pScopeRef,NvU32 internalClassId,RS_ITER_TYPE type,NvBool bExactMatch)1464 clientRefIter
1465 (
1466     RsClient *pClient,
1467     RsResourceRef *pScopeRef,
1468     NvU32 internalClassId,
1469     RS_ITER_TYPE type,
1470     NvBool bExactMatch
1471 )
1472 {
1473     RS_ITERATOR it;
1474     RsIndex *pIndex = NULL;
1475     NvBool bChildrenOnly = (type == RS_ITERATE_CHILDREN);
1476     NvBool bCachedOnly = (type == RS_ITERATE_CACHED);
1477     NvBool bDependantsOnly = (type == RS_ITERATE_DEPENDANTS);
1478     portMemSet(&it, 0, sizeof(it));
1479 
1480     if (pClient == NULL)
1481     {
1482         NV_ASSERT(0);
1483         return it;
1484     }
1485 
1486     if (pScopeRef == NULL)
1487     {
1488         if (NV_OK != clientGetResourceRef(pClient, pClient->hClient, &pScopeRef))
1489             return it;
1490     }
1491 
1492     if (bChildrenOnly || bCachedOnly || bDependantsOnly)
1493     {
1494         NvBool bIterAll = (internalClassId == 0) || !bExactMatch;
1495 
1496         if (bChildrenOnly)
1497         {
1498             pIndex = &pScopeRef->childRefMap;
1499         }
1500         else if (bCachedOnly)
1501         {
1502             pIndex = &pScopeRef->cachedRefMap;
1503         }
1504         else if (bDependantsOnly)
1505         {
1506             pIndex = &pScopeRef->depRefMap;
1507         }
1508 
1509         if (!bIterAll && multimapFindSubmap(pIndex, internalClassId) == NULL)
1510             goto done;
1511 
1512         it.idxIt = (bIterAll)
1513             ? indexRefIterAll(pIndex)
1514             : indexRefIter(pIndex, internalClassId);
1515     }
1516     else
1517     {
1518         // Match descendants of the scope resource (specific class / any class)
1519         it.mapIt = mapIterAll(&pClient->resourceMap);
1520     }
1521 
1522     it.pClient = pClient;
1523     it.pScopeRef = pScopeRef;
1524     it.internalClassId = internalClassId;
1525     it.type = type;
1526     it.bExactMatch = bExactMatch;
1527 
1528 done:
1529     return it;
1530 }
1531 
1532 RS_ORDERED_ITERATOR
clientRefOrderedIter(RsClient * pClient,RsResourceRef * pScopeRef,NvU32 internalClassId,NvBool bExactMatch)1533 clientRefOrderedIter
1534 (
1535     RsClient *pClient,
1536     RsResourceRef *pScopeRef,
1537     NvU32 internalClassId,
1538     NvBool bExactMatch
1539 )
1540 {
1541     RS_ORDERED_ITERATOR it;
1542     RsIndex *pIndex = NULL;
1543     portMemSet(&it, 0, sizeof(it));
1544 
1545     if (pClient == NULL)
1546     {
1547         NV_ASSERT(0);
1548         return it;
1549     }
1550 
1551     if (pScopeRef == NULL)
1552     {
1553         if (NV_OK != clientGetResourceRef(pClient, pClient->hClient, &pScopeRef))
1554             return it;
1555     }
1556 
1557     it.depth = -1;
1558     pIndex = &pScopeRef->childRefMap;
1559     it.idxIt[0] = indexRefIterAll(pIndex);
1560 
1561     it.pClient = pClient;
1562     it.pScopeRef = pScopeRef;
1563     it.internalClassId = internalClassId;
1564     it.bExactMatch = bExactMatch;
1565 
1566     return it;
1567 }
1568 
1569 NvBool
clientRefOrderedIterNext(RsClient * pClient,RS_ORDERED_ITERATOR * pIt)1570 clientRefOrderedIterNext
1571 (
1572     RsClient *pClient,
1573     RS_ORDERED_ITERATOR *pIt
1574 )
1575 {
1576     RsResourceRef *pResourceRef;
1577     NvBool bNext;
1578 
1579     if ((pIt == NULL) || (pIt->pClient != pClient) || pIt->pScopeRef == NULL)
1580     {
1581         // Iterator not initialized or nothing to iterate over
1582         NV_ASSERT(pIt != NULL && pIt->pClient == NULL);
1583         return NV_FALSE;
1584     }
1585 
1586     // Iterate over the scope reference if the scope is not the client
1587     if (pIt->depth == -1)
1588     {
1589         pIt->depth = 0;
1590         if ((pIt->pScopeRef->hResource != pIt->pClient->hClient) &&
1591             ((pIt->internalClassId == 0) || (pIt->internalClassId == pIt->pScopeRef->internalClassId)) &&
1592             (pIt->pScopeRef->pResource != NULL))
1593         {
1594             pIt->pResourceRef = pIt->pScopeRef;
1595             return NV_TRUE;
1596         }
1597     }
1598 
1599     pIt->pResourceRef = NULL;
1600 
1601     bNext = NV_TRUE;
1602     while (1)
1603     {
1604         // Get the next sibling, or else backtrack to parent and get its next sibling
1605         do
1606         {
1607             if (!bNext)
1608                 --pIt->depth;
1609             bNext = indexRefIterNext(&pIt->idxIt[pIt->depth]);
1610         } while (!bNext && pIt->depth != 0);
1611 
1612         if (!bNext)
1613             break;
1614 
1615         pResourceRef = *pIt->idxIt[pIt->depth].pValue;
1616 
1617         // Iterate over this resource's children next (up to max depth)
1618         if (pIt->depth < RS_MAX_RESOURCE_DEPTH)
1619         {
1620             ++pIt->depth;
1621             pIt->idxIt[pIt->depth] = indexRefIterAll(&pResourceRef->childRefMap);
1622         }
1623 
1624         if (refHasAncestor(pResourceRef, pIt->pScopeRef))
1625         {
1626             NvBool bMatch = NV_TRUE;
1627             if (pIt->internalClassId != 0)
1628             {
1629                 if (pIt->bExactMatch && (pIt->internalClassId != pResourceRef->internalClassId))
1630                     bMatch = NV_FALSE;
1631 
1632                 if (!pIt->bExactMatch && objDynamicCastById(pResourceRef->pResource, pIt->internalClassId) == NULL)
1633                     bMatch = NV_FALSE;
1634             }
1635 
1636             if (bMatch && (pResourceRef->pResource != NULL))
1637             {
1638                 pIt->pResourceRef = pResourceRef;
1639                 return NV_TRUE;
1640             }
1641         }
1642     }
1643 
1644     return NV_FALSE;
1645 }
1646 
1647 NvBool
clientRefIterNext(RsClient * pClient,RS_ITERATOR * pIt)1648 clientRefIterNext
1649 (
1650     RsClient *pClient,
1651     RS_ITERATOR *pIt
1652 )
1653 {
1654     RsResourceRef *pResourceRef;
1655     NvBool bLoop;
1656     NvBool bUseIdx;
1657 
1658     if ((pIt == NULL) || (pIt->pClient != pClient) || pIt->pScopeRef == NULL)
1659     {
1660         // Iterator not initialized or nothing to iterate over
1661         NV_ASSERT(pIt != NULL && pIt->pClient == NULL);
1662         return NV_FALSE;
1663     }
1664 
1665     bUseIdx = (pIt->type == RS_ITERATE_CACHED) ||
1666               (pIt->type == RS_ITERATE_CHILDREN) ||
1667               (pIt->type == RS_ITERATE_DEPENDANTS);
1668 
1669     pIt->pResourceRef = NULL;
1670 
1671     bLoop = bUseIdx ? indexRefIterNext(&pIt->idxIt) : mapIterNext(&pIt->mapIt);
1672     while (bLoop)
1673     {
1674         pResourceRef = bUseIdx ? *pIt->idxIt.pValue : pIt->mapIt.pValue;
1675 
1676         if (bUseIdx ||
1677             ((pResourceRef == pIt->pScopeRef) ||
1678              (refHasAncestor(pResourceRef, pIt->pScopeRef))))
1679         {
1680             NvBool bMatch = NV_TRUE;
1681             if (pIt->internalClassId != 0)
1682             {
1683                 if (pIt->bExactMatch && (pIt->internalClassId != pResourceRef->internalClassId))
1684                     bMatch = NV_FALSE;
1685 
1686                 if (!pIt->bExactMatch && objDynamicCastById(pResourceRef->pResource, pIt->internalClassId) == NULL)
1687                     bMatch = NV_FALSE;
1688             }
1689 
1690             if (bMatch && (pResourceRef->pResource != NULL))
1691             {
1692                 pIt->pResourceRef = pResourceRef;
1693                 return NV_TRUE;
1694             }
1695         }
1696 
1697         bLoop = bUseIdx ? indexRefIterNext(&pIt->idxIt) : mapIterNext(&pIt->mapIt);
1698     }
1699 
1700     return NV_FALSE;
1701 }
1702 
1703 NV_STATUS
clientPostProcessPendingFreeList_IMPL(RsClient * pClient,RsResourceRef ** ppFirstLowPriRef)1704 clientPostProcessPendingFreeList_IMPL
1705 (
1706     RsClient *pClient,
1707     RsResourceRef **ppFirstLowPriRef
1708 )
1709 {
1710     if (ppFirstLowPriRef != NULL)
1711         *ppFirstLowPriRef = NULL;
1712 
1713     return NV_OK;
1714 }
1715 
1716 NV_STATUS
clientAddAccessBackRef_IMPL(RsClient * pClient,RsResourceRef * pResourceRef)1717 clientAddAccessBackRef_IMPL
1718 (
1719     RsClient *pClient,
1720     RsResourceRef *pResourceRef
1721 )
1722 {
1723     AccessBackRef *pAccessBackRef = listPrependNew(&pClient->accessBackRefList);;
1724 
1725     if (pAccessBackRef == NULL)
1726         return NV_ERR_INSUFFICIENT_RESOURCES;
1727 
1728     pAccessBackRef->hClient = pResourceRef->pClient->hClient;
1729     pAccessBackRef->hResource = pResourceRef->hResource;
1730 
1731     return NV_OK;
1732 }
1733 
clientFreeAccessBackRefs_IMPL(RsClient * pClient,RsServer * pServer)1734 void clientFreeAccessBackRefs_IMPL
1735 (
1736     RsClient *pClient,
1737     RsServer *pServer
1738 )
1739 {
1740     AccessBackRef *pAccessBackRef;
1741     NV_STATUS      status;
1742 
1743     while ((pAccessBackRef = listHead(&pClient->accessBackRefList)) != NULL)
1744     {
1745         RsClient *pSharedClient;
1746 
1747         //
1748         // Remove access rights entry if client/resource pair is still in use
1749         // so that another client doesn't get unauthorized access to them
1750         //
1751         status = serverGetClientUnderLock(pServer, pAccessBackRef->hClient, &pSharedClient);
1752         if (status == NV_OK)
1753         {
1754             RsResourceRef *pResourceRef;
1755 
1756             status = clientGetResourceRef(pSharedClient, pAccessBackRef->hResource, &pResourceRef);
1757             if (status == NV_OK)
1758             {
1759                 RS_SHARE_POLICY revokePolicy;
1760 
1761                 revokePolicy.type = RS_SHARE_TYPE_CLIENT;
1762                 revokePolicy.target = pClient->hClient;
1763                 revokePolicy.action = RS_SHARE_ACTION_FLAG_REVOKE;
1764                 RS_ACCESS_MASK_FILL(&revokePolicy.accessMask);
1765 
1766                 // Check the resource's share policy for matching client policies
1767                 rsShareListRemove(&pResourceRef->sharePolicyList, &revokePolicy, NULL);
1768             }
1769         }
1770 
1771         listRemove(&pClient->accessBackRefList, pAccessBackRef);
1772     }
1773 }
1774