1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Module Name: utalloc - local memory allocation routines |
5 | * |
6 | * Copyright (C) 2000 - 2023, Intel Corp. |
7 | * |
8 | *****************************************************************************/ |
9 | |
10 | #include <acpi/acpi.h> |
11 | #include "accommon.h" |
12 | #include "acdebug.h" |
13 | |
14 | #define _COMPONENT ACPI_UTILITIES |
15 | ACPI_MODULE_NAME("utalloc" ) |
16 | |
17 | #if !defined (USE_NATIVE_ALLOCATE_ZEROED) |
18 | /******************************************************************************* |
19 | * |
20 | * FUNCTION: acpi_os_allocate_zeroed |
21 | * |
22 | * PARAMETERS: size - Size of the allocation |
23 | * |
24 | * RETURN: Address of the allocated memory on success, NULL on failure. |
25 | * |
26 | * DESCRIPTION: Subsystem equivalent of calloc. Allocate and zero memory. |
27 | * This is the default implementation. Can be overridden via the |
28 | * USE_NATIVE_ALLOCATE_ZEROED flag. |
29 | * |
30 | ******************************************************************************/ |
31 | void *acpi_os_allocate_zeroed(acpi_size size) |
32 | { |
33 | void *allocation; |
34 | |
35 | ACPI_FUNCTION_ENTRY(); |
36 | |
37 | allocation = acpi_os_allocate(size); |
38 | if (allocation) { |
39 | |
40 | /* Clear the memory block */ |
41 | |
42 | memset(allocation, 0, size); |
43 | } |
44 | |
45 | return (allocation); |
46 | } |
47 | |
48 | #endif /* !USE_NATIVE_ALLOCATE_ZEROED */ |
49 | |
50 | /******************************************************************************* |
51 | * |
52 | * FUNCTION: acpi_ut_create_caches |
53 | * |
54 | * PARAMETERS: None |
55 | * |
56 | * RETURN: Status |
57 | * |
58 | * DESCRIPTION: Create all local caches |
59 | * |
60 | ******************************************************************************/ |
61 | |
62 | acpi_status acpi_ut_create_caches(void) |
63 | { |
64 | acpi_status status; |
65 | |
66 | /* Object Caches, for frequently used objects */ |
67 | |
68 | status = |
69 | acpi_os_create_cache(cache_name: "Acpi-Namespace" , |
70 | object_size: sizeof(struct acpi_namespace_node), |
71 | ACPI_MAX_NAMESPACE_CACHE_DEPTH, |
72 | return_cache: &acpi_gbl_namespace_cache); |
73 | if (ACPI_FAILURE(status)) { |
74 | return (status); |
75 | } |
76 | |
77 | status = |
78 | acpi_os_create_cache(cache_name: "Acpi-State" , object_size: sizeof(union acpi_generic_state), |
79 | ACPI_MAX_STATE_CACHE_DEPTH, |
80 | return_cache: &acpi_gbl_state_cache); |
81 | if (ACPI_FAILURE(status)) { |
82 | return (status); |
83 | } |
84 | |
85 | status = |
86 | acpi_os_create_cache(cache_name: "Acpi-Parse" , |
87 | object_size: sizeof(struct acpi_parse_obj_common), |
88 | ACPI_MAX_PARSE_CACHE_DEPTH, |
89 | return_cache: &acpi_gbl_ps_node_cache); |
90 | if (ACPI_FAILURE(status)) { |
91 | return (status); |
92 | } |
93 | |
94 | status = |
95 | acpi_os_create_cache(cache_name: "Acpi-ParseExt" , |
96 | object_size: sizeof(struct acpi_parse_obj_named), |
97 | ACPI_MAX_EXTPARSE_CACHE_DEPTH, |
98 | return_cache: &acpi_gbl_ps_node_ext_cache); |
99 | if (ACPI_FAILURE(status)) { |
100 | return (status); |
101 | } |
102 | |
103 | status = |
104 | acpi_os_create_cache(cache_name: "Acpi-Operand" , |
105 | object_size: sizeof(union acpi_operand_object), |
106 | ACPI_MAX_OBJECT_CACHE_DEPTH, |
107 | return_cache: &acpi_gbl_operand_cache); |
108 | if (ACPI_FAILURE(status)) { |
109 | return (status); |
110 | } |
111 | #ifdef ACPI_ASL_COMPILER |
112 | /* |
113 | * For use with the ASL-/ASL+ option. This cache keeps track of regular |
114 | * 0xA9 0x01 comments. |
115 | */ |
116 | status = |
117 | acpi_os_create_cache("Acpi-Comment" , |
118 | sizeof(struct acpi_comment_node), |
119 | ACPI_MAX_COMMENT_CACHE_DEPTH, |
120 | &acpi_gbl_reg_comment_cache); |
121 | if (ACPI_FAILURE(status)) { |
122 | return (status); |
123 | } |
124 | |
125 | /* |
126 | * This cache keeps track of the starting addresses of where the comments |
127 | * lie. This helps prevent duplication of comments. |
128 | */ |
129 | status = |
130 | acpi_os_create_cache("Acpi-Comment-Addr" , |
131 | sizeof(struct acpi_comment_addr_node), |
132 | ACPI_MAX_COMMENT_CACHE_DEPTH, |
133 | &acpi_gbl_comment_addr_cache); |
134 | if (ACPI_FAILURE(status)) { |
135 | return (status); |
136 | } |
137 | |
138 | /* |
139 | * This cache will be used for nodes that represent files. |
140 | */ |
141 | status = |
142 | acpi_os_create_cache("Acpi-File" , sizeof(struct acpi_file_node), |
143 | ACPI_MAX_COMMENT_CACHE_DEPTH, |
144 | &acpi_gbl_file_cache); |
145 | if (ACPI_FAILURE(status)) { |
146 | return (status); |
147 | } |
148 | #endif |
149 | |
150 | #ifdef ACPI_DBG_TRACK_ALLOCATIONS |
151 | |
152 | /* Memory allocation lists */ |
153 | |
154 | status = acpi_ut_create_list("Acpi-Global" , 0, &acpi_gbl_global_list); |
155 | if (ACPI_FAILURE(status)) { |
156 | return (status); |
157 | } |
158 | |
159 | status = |
160 | acpi_ut_create_list("Acpi-Namespace" , |
161 | sizeof(struct acpi_namespace_node), |
162 | &acpi_gbl_ns_node_list); |
163 | if (ACPI_FAILURE(status)) { |
164 | return (status); |
165 | } |
166 | #endif |
167 | |
168 | return (AE_OK); |
169 | } |
170 | |
171 | /******************************************************************************* |
172 | * |
173 | * FUNCTION: acpi_ut_delete_caches |
174 | * |
175 | * PARAMETERS: None |
176 | * |
177 | * RETURN: Status |
178 | * |
179 | * DESCRIPTION: Purge and delete all local caches |
180 | * |
181 | ******************************************************************************/ |
182 | |
183 | acpi_status acpi_ut_delete_caches(void) |
184 | { |
185 | #ifdef ACPI_DBG_TRACK_ALLOCATIONS |
186 | char buffer[7]; |
187 | |
188 | if (acpi_gbl_display_final_mem_stats) { |
189 | strcpy(buffer, "MEMORY" ); |
190 | (void)acpi_db_display_statistics(buffer); |
191 | } |
192 | #endif |
193 | |
194 | (void)acpi_os_delete_cache(cache: acpi_gbl_namespace_cache); |
195 | acpi_gbl_namespace_cache = NULL; |
196 | |
197 | (void)acpi_os_delete_cache(cache: acpi_gbl_state_cache); |
198 | acpi_gbl_state_cache = NULL; |
199 | |
200 | (void)acpi_os_delete_cache(cache: acpi_gbl_operand_cache); |
201 | acpi_gbl_operand_cache = NULL; |
202 | |
203 | (void)acpi_os_delete_cache(cache: acpi_gbl_ps_node_cache); |
204 | acpi_gbl_ps_node_cache = NULL; |
205 | |
206 | (void)acpi_os_delete_cache(cache: acpi_gbl_ps_node_ext_cache); |
207 | acpi_gbl_ps_node_ext_cache = NULL; |
208 | |
209 | #ifdef ACPI_ASL_COMPILER |
210 | (void)acpi_os_delete_cache(acpi_gbl_reg_comment_cache); |
211 | acpi_gbl_reg_comment_cache = NULL; |
212 | |
213 | (void)acpi_os_delete_cache(acpi_gbl_comment_addr_cache); |
214 | acpi_gbl_comment_addr_cache = NULL; |
215 | |
216 | (void)acpi_os_delete_cache(acpi_gbl_file_cache); |
217 | acpi_gbl_file_cache = NULL; |
218 | #endif |
219 | |
220 | #ifdef ACPI_DBG_TRACK_ALLOCATIONS |
221 | |
222 | /* Debug only - display leftover memory allocation, if any */ |
223 | |
224 | acpi_ut_dump_allocations(ACPI_UINT32_MAX, NULL); |
225 | |
226 | /* Free memory lists */ |
227 | |
228 | acpi_os_free(acpi_gbl_global_list); |
229 | acpi_gbl_global_list = NULL; |
230 | |
231 | acpi_os_free(acpi_gbl_ns_node_list); |
232 | acpi_gbl_ns_node_list = NULL; |
233 | #endif |
234 | |
235 | return (AE_OK); |
236 | } |
237 | |
238 | /******************************************************************************* |
239 | * |
240 | * FUNCTION: acpi_ut_validate_buffer |
241 | * |
242 | * PARAMETERS: buffer - Buffer descriptor to be validated |
243 | * |
244 | * RETURN: Status |
245 | * |
246 | * DESCRIPTION: Perform parameter validation checks on an struct acpi_buffer |
247 | * |
248 | ******************************************************************************/ |
249 | |
250 | acpi_status acpi_ut_validate_buffer(struct acpi_buffer *buffer) |
251 | { |
252 | |
253 | /* Obviously, the structure pointer must be valid */ |
254 | |
255 | if (!buffer) { |
256 | return (AE_BAD_PARAMETER); |
257 | } |
258 | |
259 | /* Special semantics for the length */ |
260 | |
261 | if ((buffer->length == ACPI_NO_BUFFER) || |
262 | (buffer->length == ACPI_ALLOCATE_BUFFER) || |
263 | (buffer->length == ACPI_ALLOCATE_LOCAL_BUFFER)) { |
264 | return (AE_OK); |
265 | } |
266 | |
267 | /* Length is valid, the buffer pointer must be also */ |
268 | |
269 | if (!buffer->pointer) { |
270 | return (AE_BAD_PARAMETER); |
271 | } |
272 | |
273 | return (AE_OK); |
274 | } |
275 | |
276 | /******************************************************************************* |
277 | * |
278 | * FUNCTION: acpi_ut_initialize_buffer |
279 | * |
280 | * PARAMETERS: buffer - Buffer to be validated |
281 | * required_length - Length needed |
282 | * |
283 | * RETURN: Status |
284 | * |
285 | * DESCRIPTION: Validate that the buffer is of the required length or |
286 | * allocate a new buffer. Returned buffer is always zeroed. |
287 | * |
288 | ******************************************************************************/ |
289 | |
290 | acpi_status |
291 | acpi_ut_initialize_buffer(struct acpi_buffer *buffer, acpi_size required_length) |
292 | { |
293 | acpi_size input_buffer_length; |
294 | |
295 | /* Parameter validation */ |
296 | |
297 | if (!buffer || !required_length) { |
298 | return (AE_BAD_PARAMETER); |
299 | } |
300 | |
301 | /* |
302 | * Buffer->Length is used as both an input and output parameter. Get the |
303 | * input actual length and set the output required buffer length. |
304 | */ |
305 | input_buffer_length = buffer->length; |
306 | buffer->length = required_length; |
307 | |
308 | /* |
309 | * The input buffer length contains the actual buffer length, or the type |
310 | * of buffer to be allocated by this routine. |
311 | */ |
312 | switch (input_buffer_length) { |
313 | case ACPI_NO_BUFFER: |
314 | |
315 | /* Return the exception (and the required buffer length) */ |
316 | |
317 | return (AE_BUFFER_OVERFLOW); |
318 | |
319 | case ACPI_ALLOCATE_BUFFER: |
320 | /* |
321 | * Allocate a new buffer. We directectly call acpi_os_allocate here to |
322 | * purposefully bypass the (optionally enabled) internal allocation |
323 | * tracking mechanism since we only want to track internal |
324 | * allocations. Note: The caller should use acpi_os_free to free this |
325 | * buffer created via ACPI_ALLOCATE_BUFFER. |
326 | */ |
327 | buffer->pointer = acpi_os_allocate(size: required_length); |
328 | break; |
329 | |
330 | case ACPI_ALLOCATE_LOCAL_BUFFER: |
331 | |
332 | /* Allocate a new buffer with local interface to allow tracking */ |
333 | |
334 | buffer->pointer = ACPI_ALLOCATE(required_length); |
335 | break; |
336 | |
337 | default: |
338 | |
339 | /* Existing buffer: Validate the size of the buffer */ |
340 | |
341 | if (input_buffer_length < required_length) { |
342 | return (AE_BUFFER_OVERFLOW); |
343 | } |
344 | break; |
345 | } |
346 | |
347 | /* Validate allocation from above or input buffer pointer */ |
348 | |
349 | if (!buffer->pointer) { |
350 | return (AE_NO_MEMORY); |
351 | } |
352 | |
353 | /* Have a valid buffer, clear it */ |
354 | |
355 | memset(buffer->pointer, 0, required_length); |
356 | return (AE_OK); |
357 | } |
358 | |