1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2018-2024 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 #include "resserv/rs_client.h"
24 #include "resserv/rs_server.h"
25 #include "rmapi/client.h"
26 #include "rmapi/resource.h"
27 #include "rmapi/rmapi.h"
28 #include "rmapi/rmapi_utils.h"
29 #include "rmapi/control.h"
30 #include "ctrl/ctrlxxxx.h"
31 #include "gpu/gpu_resource.h"
32 #include "gpu/gpu.h"
33 #include "gpu_mgr/gpu_mgr.h"
34 #include "vgpu/rpc.h"
35 #include "core/locks.h"
36 
37 NV_STATUS
rmrescmnConstruct_IMPL(RmResourceCommon * pResourceCommmon)38 rmrescmnConstruct_IMPL
39 (
40     RmResourceCommon *pResourceCommmon
41 )
42 {
43     return NV_OK;
44 }
45 
46 NV_STATUS
rmresConstruct_IMPL(RmResource * pResource,CALL_CONTEXT * pCallContext,RS_RES_ALLOC_PARAMS_INTERNAL * pParams)47 rmresConstruct_IMPL
48 (
49     RmResource *pResource,
50     CALL_CONTEXT *pCallContext,
51     RS_RES_ALLOC_PARAMS_INTERNAL *pParams
52 )
53 {
54     if (RS_IS_COPY_CTOR(pParams))
55     {
56         RmResource *pSrcResource = dynamicCast(pParams->pSrcRef->pResource, RmResource);
57 
58         pResource->rpcGpuInstance = pSrcResource->rpcGpuInstance;
59         pResource->bRpcFree = pSrcResource->bRpcFree;
60     }
61     else
62     {
63         pResource->rpcGpuInstance = ~0;
64         pResource->bRpcFree = NV_FALSE;
65     }
66 
67     return NV_OK;
68 }
69 
70 NvBool
rmresAccessCallback_IMPL(RmResource * pResource,RsClient * pInvokingClient,void * pAllocParams,RsAccessRight accessRight)71 rmresAccessCallback_IMPL
72 (
73     RmResource *pResource,
74     RsClient *pInvokingClient,
75     void *pAllocParams,
76     RsAccessRight accessRight
77 )
78 {
79     NV_STATUS status;
80     RsResourceRef *pCliResRef;
81 
82     status = clientGetResourceRef(RES_GET_CLIENT(pResource),
83                                   RES_GET_CLIENT_HANDLE(pResource),
84                                   &pCliResRef);
85 
86     if (status == NV_OK)
87     {
88         // Allow access if the resource's owner would get the access right
89         if(resAccessCallback(pCliResRef->pResource, pInvokingClient, pAllocParams, accessRight))
90             return NV_TRUE;
91     }
92 
93     // Delegate to superclass
94     return resAccessCallback_IMPL(staticCast(pResource, RsResource), pInvokingClient, pAllocParams, accessRight);
95 }
96 
97 NvBool
rmresShareCallback_IMPL(RmResource * pResource,RsClient * pInvokingClient,RsResourceRef * pParentRef,RS_SHARE_POLICY * pSharePolicy)98 rmresShareCallback_IMPL
99 (
100     RmResource *pResource,
101     RsClient *pInvokingClient,
102     RsResourceRef *pParentRef,
103     RS_SHARE_POLICY *pSharePolicy
104 )
105 {
106     NV_STATUS status;
107     RsResourceRef *pCliResRef;
108 
109     //
110     // cliresShareCallback contains some require exceptions for non-GpuResource,
111     // which we don't want to hit. ClientResource doesn't normally implement these
112     // share types anyway, so we're fine with skipping them.
113     //
114     switch (pSharePolicy->type)
115     {
116         case RS_SHARE_TYPE_SMC_PARTITION:
117         case RS_SHARE_TYPE_GPU:
118         {
119             //
120             // We do not want to lock down these GpuResource-specific require policies
121             // when the check cannot be applied for other resources, so add these checks
122             // as an alternative bypass for those policies
123             //
124             if ((pSharePolicy->action & RS_SHARE_ACTION_FLAG_REQUIRE) &&
125                 (NULL == dynamicCast(pResource, GpuResource)))
126             {
127                 return NV_TRUE;
128             }
129             break;
130         }
131         case RS_SHARE_TYPE_FM_CLIENT:
132         {
133             RmClient *pSrcClient = dynamicCast(RES_GET_CLIENT(pResource), RmClient);
134             NvBool bSrcIsKernel = (pSrcClient != NULL) && (rmclientGetCachedPrivilege(pSrcClient) >= RS_PRIV_LEVEL_KERNEL);
135 
136             if (rmclientIsCapable(dynamicCast(pInvokingClient, RmClient),
137                                   NV_RM_CAP_EXT_FABRIC_MGMT) && !bSrcIsKernel)
138             {
139                 return NV_TRUE;
140             }
141             break;
142         }
143         default:
144         {
145             status = clientGetResourceRef(RES_GET_CLIENT(pResource),
146                                           RES_GET_CLIENT_HANDLE(pResource),
147                                           &pCliResRef);
148             if (status == NV_OK)
149             {
150                 // Allow sharing if the resource's owner would be shared with
151                 if (resShareCallback(pCliResRef->pResource, pInvokingClient,
152                                      pParentRef, pSharePolicy))
153                     return NV_TRUE;
154             }
155             break;
156         }
157     }
158 
159     // Delegate to superclass
160     return resShareCallback_IMPL(staticCast(pResource, RsResource),
161                                  pInvokingClient, pParentRef, pSharePolicy);
162 }
163 
serverControl_InitCookie(const struct NVOC_EXPORTED_METHOD_DEF * exportedEntry,RmCtrlExecuteCookie * pRmCtrlExecuteCookie)164 void serverControl_InitCookie
165 (
166     const struct NVOC_EXPORTED_METHOD_DEF   *exportedEntry,
167     RmCtrlExecuteCookie                     *pRmCtrlExecuteCookie
168 )
169 {
170     // Copy from NVOC exportedEntry
171     pRmCtrlExecuteCookie->cmd       = exportedEntry->methodId;
172     pRmCtrlExecuteCookie->ctrlFlags = exportedEntry->flags;
173     // One time initialization of a const variable
174     *(NvU32 *)&pRmCtrlExecuteCookie->rightsRequired.limbs[0]
175                                     = exportedEntry->accessRight;
176 }
177 
178 NV_STATUS
rmresGetMemInterMapParams_IMPL(RmResource * pRmResource,RMRES_MEM_INTER_MAP_PARAMS * pParams)179 rmresGetMemInterMapParams_IMPL
180 (
181     RmResource                 *pRmResource,
182     RMRES_MEM_INTER_MAP_PARAMS *pParams
183 )
184 {
185     return NV_ERR_INVALID_OBJECT_HANDLE;
186 }
187 
188 NV_STATUS
rmresCheckMemInterUnmap_IMPL(RmResource * pRmResource,NvBool bSubdeviceHandleProvided)189 rmresCheckMemInterUnmap_IMPL
190 (
191     RmResource *pRmResource,
192     NvBool      bSubdeviceHandleProvided
193 )
194 {
195     return NV_ERR_INVALID_OBJECT_HANDLE;
196 }
197 
198 NV_STATUS
rmresGetMemoryMappingDescriptor_IMPL(RmResource * pRmResource,struct MEMORY_DESCRIPTOR ** ppMemDesc)199 rmresGetMemoryMappingDescriptor_IMPL
200 (
201     RmResource *pRmResource,
202     struct MEMORY_DESCRIPTOR **ppMemDesc
203 )
204 {
205     return NV_ERR_NOT_SUPPORTED;
206 }
207 
208 NV_STATUS
rmresControlSerialization_Prologue_IMPL(RmResource * pResource,CALL_CONTEXT * pCallContext,RS_RES_CONTROL_PARAMS_INTERNAL * pParams)209 rmresControlSerialization_Prologue_IMPL
210 (
211     RmResource                     *pResource,
212     CALL_CONTEXT                   *pCallContext,
213     RS_RES_CONTROL_PARAMS_INTERNAL *pParams
214 )
215 {
216     OBJGPU *pGpu = gpumgrGetGpu(pResource->rpcGpuInstance);
217 
218     if (pGpu != NULL &&
219         ((IS_VIRTUAL(pGpu)    && (pParams->pCookie->ctrlFlags & RMCTRL_FLAGS_ROUTE_TO_VGPU_HOST)
220         ) || (IS_GSP_CLIENT(pGpu) && (pParams->pCookie->ctrlFlags & RMCTRL_FLAGS_ROUTE_TO_PHYSICAL))))
221     {
222         return serverSerializeCtrlDown(pCallContext, pParams->cmd, &pParams->pParams, &pParams->paramsSize, &pParams->flags);
223     }
224     else
225     {
226         NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, serverDeserializeCtrlDown(pCallContext, pParams->cmd, &pParams->pParams, &pParams->paramsSize, &pParams->flags));
227     }
228 
229     return NV_OK;
230 }
231 
232 void
rmresControlSerialization_Epilogue_IMPL(RmResource * pResource,CALL_CONTEXT * pCallContext,RS_RES_CONTROL_PARAMS_INTERNAL * pParams)233 rmresControlSerialization_Epilogue_IMPL
234 (
235     RmResource                     *pResource,
236     CALL_CONTEXT                   *pCallContext,
237     RS_RES_CONTROL_PARAMS_INTERNAL *pParams
238 )
239 {
240     OBJGPU *pGpu = gpumgrGetGpu(pResource->rpcGpuInstance);
241 
242     if (pGpu != NULL &&
243         ((IS_VIRTUAL(pGpu)    && (pParams->pCookie->ctrlFlags & RMCTRL_FLAGS_ROUTE_TO_VGPU_HOST)
244         ) || (IS_GSP_CLIENT(pGpu) && (pParams->pCookie->ctrlFlags & RMCTRL_FLAGS_ROUTE_TO_PHYSICAL))))
245     {
246         NV_ASSERT_OK(serverDeserializeCtrlUp(pCallContext, pParams->cmd, &pParams->pParams, &pParams->paramsSize, &pParams->flags));
247     }
248 
249     NV_ASSERT_OK(serverSerializeCtrlUp(pCallContext, pParams->cmd, &pParams->pParams, &pParams->paramsSize, &pParams->flags));
250     serverFreeSerializeStructures(pCallContext, pParams->pParams);
251 }
252 
253 NV_STATUS
rmresControl_Prologue_IMPL(RmResource * pResource,CALL_CONTEXT * pCallContext,RS_RES_CONTROL_PARAMS_INTERNAL * pParams)254 rmresControl_Prologue_IMPL
255 (
256     RmResource *pResource,
257     CALL_CONTEXT *pCallContext,
258     RS_RES_CONTROL_PARAMS_INTERNAL *pParams
259 )
260 {
261     NV_STATUS status = NV_OK;
262     OBJGPU *pGpu = gpumgrGetGpu(pResource->rpcGpuInstance);
263 
264     if (pGpu != NULL &&
265         ((IS_VIRTUAL(pGpu)    && (pParams->pCookie->ctrlFlags & RMCTRL_FLAGS_ROUTE_TO_VGPU_HOST)
266         ) || (IS_GSP_CLIENT(pGpu) && (pParams->pCookie->ctrlFlags & RMCTRL_FLAGS_ROUTE_TO_PHYSICAL))))
267     {
268         //
269         // GPU lock is required to protect the RPC buffers.
270         // However, some controls have  ROUTE_TO_PHYSICAL + NO_GPUS_LOCK flags set.
271         // This is not valid in offload mode, but is in monolithic.
272         // In those cases, just acquire the lock for the RPC
273         //
274         GPU_MASK gpuMaskRelease = 0;
275         if (!rmDeviceGpuLockIsOwner(pGpu->gpuInstance))
276         {
277             //
278             // Log any case where the above assumption is not true, but continue
279             // anyway. Use SAFE_LOCK_UPGRADE to try and recover in these cases.
280             //
281             NV_ASSERT(pParams->pCookie->ctrlFlags & RMCTRL_FLAGS_NO_GPUS_LOCK);
282             NV_ASSERT_OK_OR_RETURN(rmGpuGroupLockAcquire(pGpu->gpuInstance,
283                                    GPU_LOCK_GRP_SUBDEVICE,
284                                    GPU_LOCK_FLAGS_SAFE_LOCK_UPGRADE,
285                                    RM_LOCK_MODULES_RPC,
286                                    &gpuMaskRelease));
287         }
288 
289         NV_RM_RPC_CONTROL(pGpu, pParams->hClient, pParams->hObject, pParams->cmd,
290                           pParams->pParams, pParams->paramsSize, status);
291 
292         if (gpuMaskRelease != 0)
293         {
294             rmGpuGroupLockRelease(gpuMaskRelease, GPUS_LOCK_FLAGS_NONE);
295         }
296 
297         return (status == NV_OK) ? NV_WARN_NOTHING_TO_DO : status;
298     }
299 
300     return NV_OK;
301 }
302 
303 void
rmresControl_Epilogue_IMPL(RmResource * pResource,CALL_CONTEXT * pCallContext,RS_RES_CONTROL_PARAMS_INTERNAL * pParams)304 rmresControl_Epilogue_IMPL
305 (
306     RmResource                     *pResource,
307     CALL_CONTEXT                   *pCallContext,
308     RS_RES_CONTROL_PARAMS_INTERNAL *pParams
309 )
310 {
311 }
312