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