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(¶ms, 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, ¶ms, &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(¶ms, 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, ¶ms);
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(¶ms, 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, ¶ms);
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(¶ms, 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, ¶ms);
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(¶ms, 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, ¶ms);
1245 if (status != NV_OK)
1246 return status;
1247
1248 return serverInterUnmap(pServer, ¶ms);
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