exconcat.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
  2. /******************************************************************************
  3. *
  4. * Module Name: exconcat - Concatenate-type AML operators
  5. *
  6. * Copyright (C) 2000 - 2022, Intel Corp.
  7. *
  8. *****************************************************************************/
  9. #include <acpi/acpi.h>
  10. #include "accommon.h"
  11. #include "acinterp.h"
  12. #include "amlresrc.h"
  13. #define _COMPONENT ACPI_EXECUTER
  14. ACPI_MODULE_NAME("exconcat")
  15. /* Local Prototypes */
  16. static acpi_status
  17. acpi_ex_convert_to_object_type_string(union acpi_operand_object *obj_desc,
  18. union acpi_operand_object **result_desc);
  19. /*******************************************************************************
  20. *
  21. * FUNCTION: acpi_ex_do_concatenate
  22. *
  23. * PARAMETERS: operand0 - First source object
  24. * operand1 - Second source object
  25. * actual_return_desc - Where to place the return object
  26. * walk_state - Current walk state
  27. *
  28. * RETURN: Status
  29. *
  30. * DESCRIPTION: Concatenate two objects with the ACPI-defined conversion
  31. * rules as necessary.
  32. * NOTE:
  33. * Per the ACPI spec (up to 6.1), Concatenate only supports Integer,
  34. * String, and Buffer objects. However, we support all objects here
  35. * as an extension. This improves the usefulness of both Concatenate
  36. * and the Printf/Fprintf macros. The extension returns a string
  37. * describing the object type for the other objects.
  38. * 02/2016.
  39. *
  40. ******************************************************************************/
  41. acpi_status
  42. acpi_ex_do_concatenate(union acpi_operand_object *operand0,
  43. union acpi_operand_object *operand1,
  44. union acpi_operand_object **actual_return_desc,
  45. struct acpi_walk_state *walk_state)
  46. {
  47. union acpi_operand_object *local_operand0 = operand0;
  48. union acpi_operand_object *local_operand1 = operand1;
  49. union acpi_operand_object *temp_operand1 = NULL;
  50. union acpi_operand_object *return_desc;
  51. char *buffer;
  52. acpi_object_type operand0_type;
  53. acpi_object_type operand1_type;
  54. acpi_status status;
  55. ACPI_FUNCTION_TRACE(ex_do_concatenate);
  56. /* Operand 0 preprocessing */
  57. switch (operand0->common.type) {
  58. case ACPI_TYPE_INTEGER:
  59. case ACPI_TYPE_STRING:
  60. case ACPI_TYPE_BUFFER:
  61. operand0_type = operand0->common.type;
  62. break;
  63. default:
  64. /* For all other types, get the "object type" string */
  65. status =
  66. acpi_ex_convert_to_object_type_string(operand0,
  67. &local_operand0);
  68. if (ACPI_FAILURE(status)) {
  69. goto cleanup;
  70. }
  71. operand0_type = ACPI_TYPE_STRING;
  72. break;
  73. }
  74. /* Operand 1 preprocessing */
  75. switch (operand1->common.type) {
  76. case ACPI_TYPE_INTEGER:
  77. case ACPI_TYPE_STRING:
  78. case ACPI_TYPE_BUFFER:
  79. operand1_type = operand1->common.type;
  80. break;
  81. default:
  82. /* For all other types, get the "object type" string */
  83. status =
  84. acpi_ex_convert_to_object_type_string(operand1,
  85. &local_operand1);
  86. if (ACPI_FAILURE(status)) {
  87. goto cleanup;
  88. }
  89. operand1_type = ACPI_TYPE_STRING;
  90. break;
  91. }
  92. /*
  93. * Convert the second operand if necessary. The first operand (0)
  94. * determines the type of the second operand (1) (See the Data Types
  95. * section of the ACPI specification). Both object types are
  96. * guaranteed to be either Integer/String/Buffer by the operand
  97. * resolution mechanism.
  98. */
  99. switch (operand0_type) {
  100. case ACPI_TYPE_INTEGER:
  101. status =
  102. acpi_ex_convert_to_integer(local_operand1, &temp_operand1,
  103. ACPI_IMPLICIT_CONVERSION);
  104. break;
  105. case ACPI_TYPE_BUFFER:
  106. status =
  107. acpi_ex_convert_to_buffer(local_operand1, &temp_operand1);
  108. break;
  109. case ACPI_TYPE_STRING:
  110. switch (operand1_type) {
  111. case ACPI_TYPE_INTEGER:
  112. case ACPI_TYPE_STRING:
  113. case ACPI_TYPE_BUFFER:
  114. /* Other types have already been converted to string */
  115. status =
  116. acpi_ex_convert_to_string(local_operand1,
  117. &temp_operand1,
  118. ACPI_IMPLICIT_CONVERT_HEX);
  119. break;
  120. default:
  121. status = AE_OK;
  122. break;
  123. }
  124. break;
  125. default:
  126. ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X",
  127. operand0->common.type));
  128. status = AE_AML_INTERNAL;
  129. }
  130. if (ACPI_FAILURE(status)) {
  131. goto cleanup;
  132. }
  133. /* Take care with any newly created operand objects */
  134. if ((local_operand1 != operand1) && (local_operand1 != temp_operand1)) {
  135. acpi_ut_remove_reference(local_operand1);
  136. }
  137. local_operand1 = temp_operand1;
  138. /*
  139. * Both operands are now known to be the same object type
  140. * (Both are Integer, String, or Buffer), and we can now perform
  141. * the concatenation.
  142. *
  143. * There are three cases to handle, as per the ACPI spec:
  144. *
  145. * 1) Two Integers concatenated to produce a new Buffer
  146. * 2) Two Strings concatenated to produce a new String
  147. * 3) Two Buffers concatenated to produce a new Buffer
  148. */
  149. switch (operand0_type) {
  150. case ACPI_TYPE_INTEGER:
  151. /* Result of two Integers is a Buffer */
  152. /* Need enough buffer space for two integers */
  153. return_desc = acpi_ut_create_buffer_object((acpi_size)
  154. ACPI_MUL_2
  155. (acpi_gbl_integer_byte_width));
  156. if (!return_desc) {
  157. status = AE_NO_MEMORY;
  158. goto cleanup;
  159. }
  160. buffer = (char *)return_desc->buffer.pointer;
  161. /* Copy the first integer, LSB first */
  162. memcpy(buffer, &operand0->integer.value,
  163. acpi_gbl_integer_byte_width);
  164. /* Copy the second integer (LSB first) after the first */
  165. memcpy(buffer + acpi_gbl_integer_byte_width,
  166. &local_operand1->integer.value,
  167. acpi_gbl_integer_byte_width);
  168. break;
  169. case ACPI_TYPE_STRING:
  170. /* Result of two Strings is a String */
  171. return_desc = acpi_ut_create_string_object(((acpi_size)
  172. local_operand0->
  173. string.length +
  174. local_operand1->
  175. string.length));
  176. if (!return_desc) {
  177. status = AE_NO_MEMORY;
  178. goto cleanup;
  179. }
  180. buffer = return_desc->string.pointer;
  181. /* Concatenate the strings */
  182. strcpy(buffer, local_operand0->string.pointer);
  183. strcat(buffer, local_operand1->string.pointer);
  184. break;
  185. case ACPI_TYPE_BUFFER:
  186. /* Result of two Buffers is a Buffer */
  187. return_desc = acpi_ut_create_buffer_object(((acpi_size)
  188. operand0->buffer.
  189. length +
  190. local_operand1->
  191. buffer.length));
  192. if (!return_desc) {
  193. status = AE_NO_MEMORY;
  194. goto cleanup;
  195. }
  196. buffer = (char *)return_desc->buffer.pointer;
  197. /* Concatenate the buffers */
  198. memcpy(buffer, operand0->buffer.pointer,
  199. operand0->buffer.length);
  200. memcpy(buffer + operand0->buffer.length,
  201. local_operand1->buffer.pointer,
  202. local_operand1->buffer.length);
  203. break;
  204. default:
  205. /* Invalid object type, should not happen here */
  206. ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X",
  207. operand0->common.type));
  208. status = AE_AML_INTERNAL;
  209. goto cleanup;
  210. }
  211. *actual_return_desc = return_desc;
  212. cleanup:
  213. if (local_operand0 != operand0) {
  214. acpi_ut_remove_reference(local_operand0);
  215. }
  216. if (local_operand1 != operand1) {
  217. acpi_ut_remove_reference(local_operand1);
  218. }
  219. return_ACPI_STATUS(status);
  220. }
  221. /*******************************************************************************
  222. *
  223. * FUNCTION: acpi_ex_convert_to_object_type_string
  224. *
  225. * PARAMETERS: obj_desc - Object to be converted
  226. * return_desc - Where to place the return object
  227. *
  228. * RETURN: Status
  229. *
  230. * DESCRIPTION: Convert an object of arbitrary type to a string object that
  231. * contains the namestring for the object. Used for the
  232. * concatenate operator.
  233. *
  234. ******************************************************************************/
  235. static acpi_status
  236. acpi_ex_convert_to_object_type_string(union acpi_operand_object *obj_desc,
  237. union acpi_operand_object **result_desc)
  238. {
  239. union acpi_operand_object *return_desc;
  240. const char *type_string;
  241. type_string = acpi_ut_get_type_name(obj_desc->common.type);
  242. return_desc = acpi_ut_create_string_object(((acpi_size)strlen(type_string) + 9)); /* 9 For "[ Object]" */
  243. if (!return_desc) {
  244. return (AE_NO_MEMORY);
  245. }
  246. strcpy(return_desc->string.pointer, "[");
  247. strcat(return_desc->string.pointer, type_string);
  248. strcat(return_desc->string.pointer, " Object]");
  249. *result_desc = return_desc;
  250. return (AE_OK);
  251. }
  252. /*******************************************************************************
  253. *
  254. * FUNCTION: acpi_ex_concat_template
  255. *
  256. * PARAMETERS: operand0 - First source object
  257. * operand1 - Second source object
  258. * actual_return_desc - Where to place the return object
  259. * walk_state - Current walk state
  260. *
  261. * RETURN: Status
  262. *
  263. * DESCRIPTION: Concatenate two resource templates
  264. *
  265. ******************************************************************************/
  266. acpi_status
  267. acpi_ex_concat_template(union acpi_operand_object *operand0,
  268. union acpi_operand_object *operand1,
  269. union acpi_operand_object **actual_return_desc,
  270. struct acpi_walk_state *walk_state)
  271. {
  272. acpi_status status;
  273. union acpi_operand_object *return_desc;
  274. u8 *new_buf;
  275. u8 *end_tag;
  276. acpi_size length0;
  277. acpi_size length1;
  278. acpi_size new_length;
  279. ACPI_FUNCTION_TRACE(ex_concat_template);
  280. /*
  281. * Find the end_tag descriptor in each resource template.
  282. * Note1: returned pointers point TO the end_tag, not past it.
  283. * Note2: zero-length buffers are allowed; treated like one end_tag
  284. */
  285. /* Get the length of the first resource template */
  286. status = acpi_ut_get_resource_end_tag(operand0, &end_tag);
  287. if (ACPI_FAILURE(status)) {
  288. return_ACPI_STATUS(status);
  289. }
  290. length0 = ACPI_PTR_DIFF(end_tag, operand0->buffer.pointer);
  291. /* Get the length of the second resource template */
  292. status = acpi_ut_get_resource_end_tag(operand1, &end_tag);
  293. if (ACPI_FAILURE(status)) {
  294. return_ACPI_STATUS(status);
  295. }
  296. length1 = ACPI_PTR_DIFF(end_tag, operand1->buffer.pointer);
  297. /* Combine both lengths, minimum size will be 2 for end_tag */
  298. new_length = length0 + length1 + sizeof(struct aml_resource_end_tag);
  299. /* Create a new buffer object for the result (with one end_tag) */
  300. return_desc = acpi_ut_create_buffer_object(new_length);
  301. if (!return_desc) {
  302. return_ACPI_STATUS(AE_NO_MEMORY);
  303. }
  304. /*
  305. * Copy the templates to the new buffer, 0 first, then 1 follows. One
  306. * end_tag descriptor is copied from Operand1.
  307. */
  308. new_buf = return_desc->buffer.pointer;
  309. memcpy(new_buf, operand0->buffer.pointer, length0);
  310. memcpy(new_buf + length0, operand1->buffer.pointer, length1);
  311. /* Insert end_tag and set the checksum to zero, means "ignore checksum" */
  312. new_buf[new_length - 1] = 0;
  313. new_buf[new_length - 2] = ACPI_RESOURCE_NAME_END_TAG | 1;
  314. /* Return the completed resource template */
  315. *actual_return_desc = return_desc;
  316. return_ACPI_STATUS(AE_OK);
  317. }