1 /*
2  * Copyright (C) 2016-2020 ARM Limited. All rights reserved.
3  *
4  * Copyright (C) 2008 The Android Open Source Project
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * You may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 #include <errno.h>
19 #include <inttypes.h>
20 #include <inttypes.h>
21 /* For error codes. */
22 #include <hardware/gralloc1.h>
23 
24 #include "mali_gralloc_buffer.h"
25 #include "mali_gralloc_formats.h"
26 #include "mali_gralloc_usages.h"
27 #include "mali_gralloc_reference.h"
28 #include "allocator/mali_gralloc_ion.h"
29 #include "gralloc_helper.h"
30 #include "format_info.h"
31 
32 
33 enum tx_direction
34 {
35 	TX_NONE = 0,
36 	TX_TO_DEVICE,
37 	TX_FROM_DEVICE,
38 	TX_BOTH,
39 };
40 
41 
get_tx_direction(const uint64_t usage)42 static enum tx_direction get_tx_direction(const uint64_t usage)
43 {
44 	const bool read = (usage & GRALLOC_USAGE_SW_READ_MASK) ? true : false;
45 	const bool write = (usage & GRALLOC_USAGE_SW_WRITE_MASK) ? true : false;
46 	enum tx_direction dir = TX_NONE;
47 
48 	if (read && write)
49 	{
50 		dir = TX_BOTH;
51 	}
52 	else if (write)
53 	{
54 		dir = TX_TO_DEVICE;
55 	}
56 	else if (read)
57 	{
58 		dir = TX_FROM_DEVICE;
59 	}
60 
61 	return dir;
62 }
63 
buffer_sync(private_handle_t * const hnd,const enum tx_direction direction)64 static void buffer_sync(private_handle_t * const hnd,
65                         const enum tx_direction direction)
66 {
67 	if (direction != TX_NONE)
68 	{
69 		hnd->cpu_read = (direction == TX_FROM_DEVICE || direction == TX_BOTH) ? 1 : 0;
70 		hnd->cpu_write = (direction == TX_TO_DEVICE || direction == TX_BOTH) ? 1 : 0;
71 
72 #if defined(GRALLOC_ION_SYNC_ON_LOCK) && GRALLOC_ION_SYNC_ON_LOCK == 1
73 		const int status = mali_gralloc_ion_sync_start(hnd,
74 		                                               hnd->cpu_read ? true : false,
75 		                                               hnd->cpu_write ? true : false);
76 		if (status < 0)
77 		{
78 			return;
79 		}
80 #endif
81 	}
82 	else if (hnd->cpu_read || hnd->cpu_write)
83 	{
84 #if defined(GRALLOC_ION_SYNC_ON_LOCK) && GRALLOC_ION_SYNC_ON_LOCK == 1
85 		const int status = mali_gralloc_ion_sync_end(hnd,
86 		                                             hnd->cpu_read ? true : false,
87 		                                             hnd->cpu_write ? true : false);
88 		if (status < 0)
89 		{
90 			return;
91 		}
92 #endif
93 		hnd->cpu_read = 0;
94 		hnd->cpu_write = 0;
95 	}
96 }
97 
98 
99 /*
100  *  Validates input parameters of lock request.
101  *
102  * @param buffer   [in]    The buffer to lock.
103  * @param l        [in]    Access region left offset (in pixels).
104  * @param t        [in]    Access region top offset (in pixels).
105  * @param w        [in]    Access region requested width (in pixels).
106  * @param h        [in]    Access region requested height (in pixels).
107  * @param usage    [in]    Lock request (producer and consumer combined) usage.
108  *
109  * @return 0,for valid input parameters;
110  *         -EINVAL, for erroneous input parameters
111  */
validate_lock_input_parameters(const buffer_handle_t buffer,const int l,const int t,const int w,const int h,uint64_t usage)112 int validate_lock_input_parameters(const buffer_handle_t buffer, const int l,
113                                    const int t, const int w, const int h,
114                                    uint64_t usage)
115 {
116 	const private_handle_t * const hnd = (private_handle_t *)buffer;
117 
118 	/* TODO: do not check access region for blob formats.
119 	 * This is because codec2 attempts to lock with wrong access region.
120 	 * Ask Google to fix codec2
121 	 */
122 	if (hnd->get_alloc_format() != HAL_PIXEL_FORMAT_BLOB)
123 	{
124 		if ((l < 0) || (t < 0) || (w < 0) || (h < 0))
125 		{
126 			MALI_GRALLOC_LOGW("Negative values for access region (l = %d t = %d w = %d and "
127 			     "h = %d) in buffer lock request are invalid.", l, t, w, h);
128 			return -EINVAL;
129 		}
130 
131 		/* Test overflow conditions on access region parameters */
132 		if (((l + w) < 0) || ((t + h) < 0))
133 		{
134 			MALI_GRALLOC_LOGW("Encountered overflow with access region (l = %d t = %d w = %d and"
135 			     " h = %d) in buffer lock request.", l, t, w, h);
136 			return -EINVAL;
137 		}
138 
139 		/* Region of interest shall be inside the allocated buffer */
140 		if (((t + h) > hnd->height)  || ((l + w) > hnd->width))
141 		{
142 			MALI_GRALLOC_LOGW("Buffer lock access region (l = %d t = %d w = %d "
143 			     "and h = %d) is outside allocated buffer (width = %d and height = %d)",
144 			     l, t, w, h, hnd->width, hnd->height);
145 			return -EINVAL;
146 		}
147 	}
148 
149 	/* Reject lock requests for AFBC (compressed format) enabled buffers */
150 	if ((hnd->alloc_format & MALI_GRALLOC_INTFMT_EXT_MASK) != 0)
151 	{
152 		MALI_GRALLOC_LOGE("Lock is not supported for AFBC enabled buffers."
153 		     "Internal Format:0x%" PRIx64, hnd->alloc_format);
154 
155 		return GRALLOC1_ERROR_UNSUPPORTED;
156 	}
157 
158 	/* Producer and consumer usage is verified in gralloc1 specific code. */
159 	GRALLOC_UNUSED(usage);
160 
161 	return 0;
162 }
163 
164 
165 /*
166  *  Locks the given buffer for the specified CPU usage.
167  *
168  * @param m        [in]    Gralloc module.
169  * @param buffer   [in]    The buffer to lock.
170  * @param usage    [in]    Producer and consumer combined usage.
171  * @param l        [in]    Access region left offset (in pixels).
172  * @param t        [in]    Access region top offset (in pixels).
173  * @param w        [in]    Access region requested width (in pixels).
174  * @param h        [in]    Access region requested height (in pixels).
175  * @param vaddr    [out]   To be filled with a CPU-accessible pointer to
176  *                         the buffer data for CPU usage.
177  *
178  * @return 0, when the locking is successful;
179  *         Appropriate error, otherwise
180  *
181  * @Note:  There is no way to ascertain whether buffer data is valid or not (for
182  *         example, establishing if the h/w needs to finish rendering or if CPU
183  *         caches need to be synchronized).
184  *
185  * @Note:  Locking a buffer simultaneously for write or read/write leaves the
186  *         buffer's content in an indeterminate state.
187  */
mali_gralloc_lock(buffer_handle_t buffer,uint64_t usage,int l,int t,int w,int h,void ** vaddr)188 int mali_gralloc_lock(buffer_handle_t buffer,
189                       uint64_t usage, int l, int t, int w, int h, void **vaddr)
190 {
191 	int status;
192 
193 	if (mali_gralloc_reference_validate(buffer))
194 	{
195 		MALI_GRALLOC_LOGE("Locking invalid buffer %p, returning error", buffer);
196 		return -EINVAL;
197 	}
198 
199 	/* Validate input parameters for lock request */
200 	status = validate_lock_input_parameters(buffer, l, t, w, h, usage);
201 	if (status != 0)
202 	{
203 		return status;
204 	}
205 
206 	private_handle_t *hnd = (private_handle_t *)buffer;
207 
208 	const int32_t format_idx = get_format_index(hnd->alloc_format & MALI_GRALLOC_INTFMT_FMT_MASK);
209 	if (format_idx == -1)
210 	{
211 		MALI_GRALLOC_LOGE("Corrupted buffer format (%s 0x%" PRIx64 ") of buffer %p",
212 			format_name(hnd->alloc_format), hnd->alloc_format, hnd);
213 		return -EINVAL;
214 	}
215 
216 	/* Populate CPU-accessible pointer when requested for CPU usage */
217 	if ((usage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) != 0)
218 	{
219 		if (vaddr == NULL)
220 		{
221 			return -EINVAL;
222 		}
223 
224 		if (mali_gralloc_reference_map(buffer) != 0) {
225 			return -EINVAL;
226 		}
227 
228 		std::optional<void*> buf_addr = mali_gralloc_reference_get_buf_addr(buffer);
229 		if (!buf_addr.has_value()) {
230 			MALI_GRALLOC_LOGE("BUG: Invalid buffer address on a just mapped buffer");
231 			return -EINVAL;
232 		}
233 		*vaddr = buf_addr.value();
234 
235 		buffer_sync(hnd, get_tx_direction(usage));
236 		return mali_gralloc_reference_lock_retain(buffer);
237 	}
238 
239 	return 0;
240 
241 }
242 
243 
244 /*
245  *  Unlocks the given buffer.
246  *
247  * @param buffer      [in]   The buffer to unlock.
248  *
249  * @return 0, when the locking is successful;
250  *         Appropriate error, otherwise
251  */
mali_gralloc_unlock(buffer_handle_t buffer)252 int mali_gralloc_unlock(buffer_handle_t buffer)
253 {
254 	if (private_handle_t::validate(buffer) < 0)
255 	{
256 		MALI_GRALLOC_LOGE("Unlocking invalid buffer %p, returning error", buffer);
257 		return -EINVAL;
258 	}
259 
260 	private_handle_t *hnd = (private_handle_t *)buffer;
261 	buffer_sync(hnd, TX_NONE);
262 
263 	return mali_gralloc_reference_lock_release(buffer);
264 }
265