1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2014-2017 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  * @file
25  * @brief MEMORY module implementation for Unix kernelmode
26  *
27  * This implementation uses the NVIDIA OS interface into the unix kernels.
28  */
29 
30 #if !PORT_IS_KERNEL_BUILD
31 #error "This file can only be compiled as part of the kernel build."
32 #endif
33 #if !NVOS_IS_UNIX
34 #error "This file can only be compiled on Unix."
35 #endif
36 
37 #include "nvport/nvport.h"
38 #include "os-interface.h"
39 
40 /**
41  * @note All kernel memory in unix is non-paged.
42  */
43 void *
_portMemAllocPagedUntracked(NvLength lengthBytes)44 _portMemAllocPagedUntracked
45 (
46     NvLength lengthBytes
47 )
48 {
49     return _portMemAllocNonPagedUntracked(lengthBytes);
50 }
51 
52 void *
_portMemAllocNonPagedUntracked(NvLength lengthBytes)53 _portMemAllocNonPagedUntracked
54 (
55     NvLength lengthBytes
56 )
57 {
58     void *pMem = NULL;
59     PORT_ASSERT_CHECKED(lengthBytes > 0);
60     if (lengthBytes > 0)
61         os_alloc_mem(&pMem, lengthBytes);
62     return pMem;
63 }
64 
65 
66 
67 void
_portMemFreeUntracked(void * pData)68 _portMemFreeUntracked
69 (
70     void *pData
71 )
72 {
73     if (pData != NULL)
74     {
75         os_free_mem(pData);
76     }
77 }
78 
79 void *
portMemCopy(void * pDestination,NvLength destSize,const void * pSource,NvLength srcSize)80 portMemCopy
81 (
82     void       *pDestination,
83     NvLength    destSize,
84     const void *pSource,
85     NvLength    srcSize
86 )
87 {
88     // API guarantees this is a NOP when destSize==0
89     if (destSize == 0)
90     {
91         return pDestination;
92     }
93 
94     PORT_ASSERT_CHECKED(pDestination != NULL);
95     PORT_ASSERT_CHECKED(pSource      != NULL);
96     PORT_ASSERT_CHECKED(srcSize      <= destSize);
97     PORT_ASSERT_CHECKED(!portUtilCheckOverlap(pDestination, destSize,
98                                               pSource,      srcSize));
99 
100     if ((pSource == NULL) || (pDestination == NULL) || (srcSize > destSize))
101     {
102         return NULL;
103     }
104     return os_mem_copy(pDestination, pSource, srcSize);
105 }
106 
107 
108 void *
portMemSet(void * pData,NvU8 value,NvLength lengthBytes)109 portMemSet
110 (
111     void    *pData,
112     NvU8     value,
113     NvLength lengthBytes
114 )
115 {
116     if (lengthBytes == 0)
117     {
118         return pData;
119     }
120     if (pData == NULL)
121     {
122         return pData;
123     }
124     return os_mem_set(pData, value, lengthBytes);
125 }
126 
127 NvS32
portMemCmp(const void * pData0,const void * pData1,NvLength lengthBytes)128 portMemCmp
129 (
130     const void *pData0,
131     const void *pData1,
132     NvLength lengthBytes
133 )
134 {
135     if (lengthBytes == 0)
136     {
137         return 0;
138     }
139     if ((pData0 == NULL) || (pData1 == NULL))
140     {
141         return -1;
142     }
143     return os_mem_cmp(pData0, pData1, lengthBytes);
144 }
145 
146 
147 
148 #define PORT_MEM_USE_GENERIC_portMemSetPattern
149 #define PORT_MEM_USE_GENERIC_portMemMove
150 #include "memory_generic.h"
151 
152 NV_STATUS
portMemExCopyFromUser(const NvP64 pUser,void * pKernel,NvLength lengthBytes)153 portMemExCopyFromUser
154 (
155     const NvP64 pUser,
156     void       *pKernel,
157     NvLength    lengthBytes
158 )
159 {
160     if (pKernel == NULL)
161     {
162         return NV_ERR_INVALID_POINTER;
163     }
164     if (lengthBytes == 0)
165     {
166         return NV_ERR_INVALID_ARGUMENT;
167     }
168     return os_memcpy_from_user(pKernel, NvP64_VALUE(pUser), lengthBytes);
169 }
170 
171 NV_STATUS
portMemExCopyToUser(const void * pKernel,NvP64 pUser,NvLength lengthBytes)172 portMemExCopyToUser
173 (
174     const void *pKernel,
175     NvP64       pUser,
176     NvLength    lengthBytes
177 )
178 {
179     if (pKernel == NULL)
180     {
181         return NV_ERR_INVALID_POINTER;
182     }
183     if (lengthBytes == 0)
184     {
185         return NV_ERR_INVALID_ARGUMENT;
186     }
187     return os_memcpy_to_user(NvP64_VALUE(pUser), (void*)pKernel, lengthBytes);
188 }
189 
190 NvLength
portMemExGetPageSize(void)191 portMemExGetPageSize(void)
192 {
193     return os_page_size;
194 }
195 
196 // Large allocations (>KMALLOC_LIMIT) will fail, but it is safe to call
197 NvBool
portMemExSafeForPagedAlloc(void)198 portMemExSafeForPagedAlloc(void)
199 {
200     return NV_TRUE;
201 }
202 NvBool
portMemExSafeForNonPagedAlloc(void)203 portMemExSafeForNonPagedAlloc(void)
204 {
205     return NV_TRUE;
206 }
207