xref: /linux/drivers/acpi/acpica/exstorob.c (revision b6ebbac51bedf9e98e837688bc838f400196da5e)
1 /******************************************************************************
2  *
3  * Module Name: exstorob - AML object store support, store to object
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2016, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43 
44 #include <acpi/acpi.h>
45 #include "accommon.h"
46 #include "acinterp.h"
47 
48 #define _COMPONENT          ACPI_EXECUTER
49 ACPI_MODULE_NAME("exstorob")
50 
51 /*******************************************************************************
52  *
53  * FUNCTION:    acpi_ex_store_buffer_to_buffer
54  *
55  * PARAMETERS:  source_desc         - Source object to copy
56  *              target_desc         - Destination object of the copy
57  *
58  * RETURN:      Status
59  *
60  * DESCRIPTION: Copy a buffer object to another buffer object.
61  *
62  ******************************************************************************/
63 acpi_status
64 acpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc,
65 			       union acpi_operand_object *target_desc)
66 {
67 	u32 length;
68 	u8 *buffer;
69 
70 	ACPI_FUNCTION_TRACE_PTR(ex_store_buffer_to_buffer, source_desc);
71 
72 	/* If Source and Target are the same, just return */
73 
74 	if (source_desc == target_desc) {
75 		return_ACPI_STATUS(AE_OK);
76 	}
77 
78 	/* We know that source_desc is a buffer by now */
79 
80 	buffer = ACPI_CAST_PTR(u8, source_desc->buffer.pointer);
81 	length = source_desc->buffer.length;
82 
83 	/*
84 	 * If target is a buffer of length zero or is a static buffer,
85 	 * allocate a new buffer of the proper length
86 	 */
87 	if ((target_desc->buffer.length == 0) ||
88 	    (target_desc->common.flags & AOPOBJ_STATIC_POINTER)) {
89 		target_desc->buffer.pointer = ACPI_ALLOCATE(length);
90 		if (!target_desc->buffer.pointer) {
91 			return_ACPI_STATUS(AE_NO_MEMORY);
92 		}
93 
94 		target_desc->buffer.length = length;
95 	}
96 
97 	/* Copy source buffer to target buffer */
98 
99 	if (length <= target_desc->buffer.length) {
100 
101 		/* Clear existing buffer and copy in the new one */
102 
103 		memset(target_desc->buffer.pointer, 0,
104 		       target_desc->buffer.length);
105 		memcpy(target_desc->buffer.pointer, buffer, length);
106 
107 #ifdef ACPI_OBSOLETE_BEHAVIOR
108 		/*
109 		 * NOTE: ACPI versions up to 3.0 specified that the buffer must be
110 		 * truncated if the string is smaller than the buffer. However, "other"
111 		 * implementations of ACPI never did this and thus became the defacto
112 		 * standard. ACPI 3.0A changes this behavior such that the buffer
113 		 * is no longer truncated.
114 		 */
115 
116 		/*
117 		 * OBSOLETE BEHAVIOR:
118 		 * If the original source was a string, we must truncate the buffer,
119 		 * according to the ACPI spec. Integer-to-Buffer and Buffer-to-Buffer
120 		 * copy must not truncate the original buffer.
121 		 */
122 		if (original_src_type == ACPI_TYPE_STRING) {
123 
124 			/* Set the new length of the target */
125 
126 			target_desc->buffer.length = length;
127 		}
128 #endif
129 	} else {
130 		/* Truncate the source, copy only what will fit */
131 
132 		memcpy(target_desc->buffer.pointer, buffer,
133 		       target_desc->buffer.length);
134 
135 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
136 				  "Truncating source buffer from %X to %X\n",
137 				  length, target_desc->buffer.length));
138 	}
139 
140 	/* Copy flags */
141 
142 	target_desc->buffer.flags = source_desc->buffer.flags;
143 	target_desc->common.flags &= ~AOPOBJ_STATIC_POINTER;
144 	return_ACPI_STATUS(AE_OK);
145 }
146 
147 /*******************************************************************************
148  *
149  * FUNCTION:    acpi_ex_store_string_to_string
150  *
151  * PARAMETERS:  source_desc         - Source object to copy
152  *              target_desc         - Destination object of the copy
153  *
154  * RETURN:      Status
155  *
156  * DESCRIPTION: Copy a String object to another String object
157  *
158  ******************************************************************************/
159 
160 acpi_status
161 acpi_ex_store_string_to_string(union acpi_operand_object *source_desc,
162 			       union acpi_operand_object *target_desc)
163 {
164 	u32 length;
165 	u8 *buffer;
166 
167 	ACPI_FUNCTION_TRACE_PTR(ex_store_string_to_string, source_desc);
168 
169 	/* If Source and Target are the same, just return */
170 
171 	if (source_desc == target_desc) {
172 		return_ACPI_STATUS(AE_OK);
173 	}
174 
175 	/* We know that source_desc is a string by now */
176 
177 	buffer = ACPI_CAST_PTR(u8, source_desc->string.pointer);
178 	length = source_desc->string.length;
179 
180 	/*
181 	 * Replace existing string value if it will fit and the string
182 	 * pointer is not a static pointer (part of an ACPI table)
183 	 */
184 	if ((length < target_desc->string.length) &&
185 	    (!(target_desc->common.flags & AOPOBJ_STATIC_POINTER))) {
186 		/*
187 		 * String will fit in existing non-static buffer.
188 		 * Clear old string and copy in the new one
189 		 */
190 		memset(target_desc->string.pointer, 0,
191 		       (acpi_size)target_desc->string.length + 1);
192 		memcpy(target_desc->string.pointer, buffer, length);
193 	} else {
194 		/*
195 		 * Free the current buffer, then allocate a new buffer
196 		 * large enough to hold the value
197 		 */
198 		if (target_desc->string.pointer &&
199 		    (!(target_desc->common.flags & AOPOBJ_STATIC_POINTER))) {
200 
201 			/* Only free if not a pointer into the DSDT */
202 
203 			ACPI_FREE(target_desc->string.pointer);
204 		}
205 
206 		target_desc->string.pointer =
207 		    ACPI_ALLOCATE_ZEROED((acpi_size)length + 1);
208 
209 		if (!target_desc->string.pointer) {
210 			return_ACPI_STATUS(AE_NO_MEMORY);
211 		}
212 
213 		target_desc->common.flags &= ~AOPOBJ_STATIC_POINTER;
214 		memcpy(target_desc->string.pointer, buffer, length);
215 	}
216 
217 	/* Set the new target length */
218 
219 	target_desc->string.length = length;
220 	return_ACPI_STATUS(AE_OK);
221 }
222