utresrc.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  1. // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
  2. /*******************************************************************************
  3. *
  4. * Module Name: utresrc - Resource management utilities
  5. *
  6. ******************************************************************************/
  7. #include <acpi/acpi.h>
  8. #include "accommon.h"
  9. #include "acresrc.h"
  10. #define _COMPONENT ACPI_UTILITIES
  11. ACPI_MODULE_NAME("utresrc")
  12. /*
  13. * Base sizes of the raw AML resource descriptors, indexed by resource type.
  14. * Zero indicates a reserved (and therefore invalid) resource type.
  15. */
  16. const u8 acpi_gbl_resource_aml_sizes[] = {
  17. /* Small descriptors */
  18. 0,
  19. 0,
  20. 0,
  21. 0,
  22. ACPI_AML_SIZE_SMALL(struct aml_resource_irq),
  23. ACPI_AML_SIZE_SMALL(struct aml_resource_dma),
  24. ACPI_AML_SIZE_SMALL(struct aml_resource_start_dependent),
  25. ACPI_AML_SIZE_SMALL(struct aml_resource_end_dependent),
  26. ACPI_AML_SIZE_SMALL(struct aml_resource_io),
  27. ACPI_AML_SIZE_SMALL(struct aml_resource_fixed_io),
  28. ACPI_AML_SIZE_SMALL(struct aml_resource_fixed_dma),
  29. 0,
  30. 0,
  31. 0,
  32. ACPI_AML_SIZE_SMALL(struct aml_resource_vendor_small),
  33. ACPI_AML_SIZE_SMALL(struct aml_resource_end_tag),
  34. /* Large descriptors */
  35. 0,
  36. ACPI_AML_SIZE_LARGE(struct aml_resource_memory24),
  37. ACPI_AML_SIZE_LARGE(struct aml_resource_generic_register),
  38. 0,
  39. ACPI_AML_SIZE_LARGE(struct aml_resource_vendor_large),
  40. ACPI_AML_SIZE_LARGE(struct aml_resource_memory32),
  41. ACPI_AML_SIZE_LARGE(struct aml_resource_fixed_memory32),
  42. ACPI_AML_SIZE_LARGE(struct aml_resource_address32),
  43. ACPI_AML_SIZE_LARGE(struct aml_resource_address16),
  44. ACPI_AML_SIZE_LARGE(struct aml_resource_extended_irq),
  45. ACPI_AML_SIZE_LARGE(struct aml_resource_address64),
  46. ACPI_AML_SIZE_LARGE(struct aml_resource_extended_address64),
  47. ACPI_AML_SIZE_LARGE(struct aml_resource_gpio),
  48. ACPI_AML_SIZE_LARGE(struct aml_resource_pin_function),
  49. ACPI_AML_SIZE_LARGE(struct aml_resource_common_serialbus),
  50. ACPI_AML_SIZE_LARGE(struct aml_resource_pin_config),
  51. ACPI_AML_SIZE_LARGE(struct aml_resource_pin_group),
  52. ACPI_AML_SIZE_LARGE(struct aml_resource_pin_group_function),
  53. ACPI_AML_SIZE_LARGE(struct aml_resource_pin_group_config),
  54. };
  55. const u8 acpi_gbl_resource_aml_serial_bus_sizes[] = {
  56. 0,
  57. ACPI_AML_SIZE_LARGE(struct aml_resource_i2c_serialbus),
  58. ACPI_AML_SIZE_LARGE(struct aml_resource_spi_serialbus),
  59. ACPI_AML_SIZE_LARGE(struct aml_resource_uart_serialbus),
  60. };
  61. /*
  62. * Resource types, used to validate the resource length field.
  63. * The length of fixed-length types must match exactly, variable
  64. * lengths must meet the minimum required length, etc.
  65. * Zero indicates a reserved (and therefore invalid) resource type.
  66. */
  67. static const u8 acpi_gbl_resource_types[] = {
  68. /* Small descriptors */
  69. 0,
  70. 0,
  71. 0,
  72. 0,
  73. ACPI_SMALL_VARIABLE_LENGTH, /* 04 IRQ */
  74. ACPI_FIXED_LENGTH, /* 05 DMA */
  75. ACPI_SMALL_VARIABLE_LENGTH, /* 06 start_dependent_functions */
  76. ACPI_FIXED_LENGTH, /* 07 end_dependent_functions */
  77. ACPI_FIXED_LENGTH, /* 08 IO */
  78. ACPI_FIXED_LENGTH, /* 09 fixed_IO */
  79. ACPI_FIXED_LENGTH, /* 0A fixed_DMA */
  80. 0,
  81. 0,
  82. 0,
  83. ACPI_VARIABLE_LENGTH, /* 0E vendor_short */
  84. ACPI_FIXED_LENGTH, /* 0F end_tag */
  85. /* Large descriptors */
  86. 0,
  87. ACPI_FIXED_LENGTH, /* 01 Memory24 */
  88. ACPI_FIXED_LENGTH, /* 02 generic_register */
  89. 0,
  90. ACPI_VARIABLE_LENGTH, /* 04 vendor_long */
  91. ACPI_FIXED_LENGTH, /* 05 Memory32 */
  92. ACPI_FIXED_LENGTH, /* 06 memory32_fixed */
  93. ACPI_VARIABLE_LENGTH, /* 07 Dword* address */
  94. ACPI_VARIABLE_LENGTH, /* 08 Word* address */
  95. ACPI_VARIABLE_LENGTH, /* 09 extended_IRQ */
  96. ACPI_VARIABLE_LENGTH, /* 0A Qword* address */
  97. ACPI_FIXED_LENGTH, /* 0B Extended* address */
  98. ACPI_VARIABLE_LENGTH, /* 0C Gpio* */
  99. ACPI_VARIABLE_LENGTH, /* 0D pin_function */
  100. ACPI_VARIABLE_LENGTH, /* 0E *serial_bus */
  101. ACPI_VARIABLE_LENGTH, /* 0F pin_config */
  102. ACPI_VARIABLE_LENGTH, /* 10 pin_group */
  103. ACPI_VARIABLE_LENGTH, /* 11 pin_group_function */
  104. ACPI_VARIABLE_LENGTH, /* 12 pin_group_config */
  105. };
  106. /*******************************************************************************
  107. *
  108. * FUNCTION: acpi_ut_walk_aml_resources
  109. *
  110. * PARAMETERS: walk_state - Current walk info
  111. * PARAMETERS: aml - Pointer to the raw AML resource template
  112. * aml_length - Length of the entire template
  113. * user_function - Called once for each descriptor found. If
  114. * NULL, a pointer to the end_tag is returned
  115. * context - Passed to user_function
  116. *
  117. * RETURN: Status
  118. *
  119. * DESCRIPTION: Walk a raw AML resource list(buffer). User function called
  120. * once for each resource found.
  121. *
  122. ******************************************************************************/
  123. acpi_status
  124. acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state,
  125. u8 *aml,
  126. acpi_size aml_length,
  127. acpi_walk_aml_callback user_function, void **context)
  128. {
  129. acpi_status status;
  130. u8 *end_aml;
  131. u8 resource_index;
  132. u32 length;
  133. u32 offset = 0;
  134. u8 end_tag[2] = { 0x79, 0x00 };
  135. ACPI_FUNCTION_TRACE(ut_walk_aml_resources);
  136. /* The absolute minimum resource template is one end_tag descriptor */
  137. if (aml_length < sizeof(struct aml_resource_end_tag)) {
  138. return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
  139. }
  140. /* Point to the end of the resource template buffer */
  141. end_aml = aml + aml_length;
  142. /* Walk the byte list, abort on any invalid descriptor type or length */
  143. while (aml < end_aml) {
  144. /* Validate the Resource Type and Resource Length */
  145. status =
  146. acpi_ut_validate_resource(walk_state, aml, &resource_index);
  147. if (ACPI_FAILURE(status)) {
  148. /*
  149. * Exit on failure. Cannot continue because the descriptor
  150. * length may be bogus also.
  151. */
  152. return_ACPI_STATUS(status);
  153. }
  154. /* Get the length of this descriptor */
  155. length = acpi_ut_get_descriptor_length(aml);
  156. /* Invoke the user function */
  157. if (user_function) {
  158. status =
  159. user_function(aml, length, offset, resource_index,
  160. context);
  161. if (ACPI_FAILURE(status)) {
  162. return_ACPI_STATUS(status);
  163. }
  164. }
  165. /* An end_tag descriptor terminates this resource template */
  166. if (acpi_ut_get_resource_type(aml) ==
  167. ACPI_RESOURCE_NAME_END_TAG) {
  168. /*
  169. * There must be at least one more byte in the buffer for
  170. * the 2nd byte of the end_tag
  171. */
  172. if ((aml + 1) >= end_aml) {
  173. return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
  174. }
  175. /*
  176. * Don't attempt to perform any validation on the 2nd byte.
  177. * Although all known ASL compilers insert a zero for the 2nd
  178. * byte, it can also be a checksum (as per the ACPI spec),
  179. * and this is occasionally seen in the field. July 2017.
  180. */
  181. /* Return the pointer to the end_tag if requested */
  182. if (!user_function) {
  183. *context = aml;
  184. }
  185. /* Normal exit */
  186. return_ACPI_STATUS(AE_OK);
  187. }
  188. aml += length;
  189. offset += length;
  190. }
  191. /* Did not find an end_tag descriptor */
  192. if (user_function) {
  193. /* Insert an end_tag anyway. acpi_rs_get_list_length always leaves room */
  194. (void)acpi_ut_validate_resource(walk_state, end_tag,
  195. &resource_index);
  196. status =
  197. user_function(end_tag, 2, offset, resource_index, context);
  198. if (ACPI_FAILURE(status)) {
  199. return_ACPI_STATUS(status);
  200. }
  201. }
  202. return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
  203. }
  204. /*******************************************************************************
  205. *
  206. * FUNCTION: acpi_ut_validate_resource
  207. *
  208. * PARAMETERS: walk_state - Current walk info
  209. * aml - Pointer to the raw AML resource descriptor
  210. * return_index - Where the resource index is returned. NULL
  211. * if the index is not required.
  212. *
  213. * RETURN: Status, and optionally the Index into the global resource tables
  214. *
  215. * DESCRIPTION: Validate an AML resource descriptor by checking the Resource
  216. * Type and Resource Length. Returns an index into the global
  217. * resource information/dispatch tables for later use.
  218. *
  219. ******************************************************************************/
  220. acpi_status
  221. acpi_ut_validate_resource(struct acpi_walk_state *walk_state,
  222. void *aml, u8 *return_index)
  223. {
  224. union aml_resource *aml_resource;
  225. u8 resource_type;
  226. u8 resource_index;
  227. acpi_rs_length resource_length;
  228. acpi_rs_length minimum_resource_length;
  229. ACPI_FUNCTION_ENTRY();
  230. /*
  231. * 1) Validate the resource_type field (Byte 0)
  232. */
  233. resource_type = ACPI_GET8(aml);
  234. /*
  235. * Byte 0 contains the descriptor name (Resource Type)
  236. * Examine the large/small bit in the resource header
  237. */
  238. if (resource_type & ACPI_RESOURCE_NAME_LARGE) {
  239. /* Verify the large resource type (name) against the max */
  240. if (resource_type > ACPI_RESOURCE_NAME_LARGE_MAX) {
  241. goto invalid_resource;
  242. }
  243. /*
  244. * Large Resource Type -- bits 6:0 contain the name
  245. * Translate range 0x80-0x8B to index range 0x10-0x1B
  246. */
  247. resource_index = (u8) (resource_type - 0x70);
  248. } else {
  249. /*
  250. * Small Resource Type -- bits 6:3 contain the name
  251. * Shift range to index range 0x00-0x0F
  252. */
  253. resource_index = (u8)
  254. ((resource_type & ACPI_RESOURCE_NAME_SMALL_MASK) >> 3);
  255. }
  256. /*
  257. * Check validity of the resource type, via acpi_gbl_resource_types.
  258. * Zero indicates an invalid resource.
  259. */
  260. if (!acpi_gbl_resource_types[resource_index]) {
  261. goto invalid_resource;
  262. }
  263. /*
  264. * Validate the resource_length field. This ensures that the length
  265. * is at least reasonable, and guarantees that it is non-zero.
  266. */
  267. resource_length = acpi_ut_get_resource_length(aml);
  268. minimum_resource_length = acpi_gbl_resource_aml_sizes[resource_index];
  269. /* Validate based upon the type of resource - fixed length or variable */
  270. switch (acpi_gbl_resource_types[resource_index]) {
  271. case ACPI_FIXED_LENGTH:
  272. /* Fixed length resource, length must match exactly */
  273. if (resource_length != minimum_resource_length) {
  274. goto bad_resource_length;
  275. }
  276. break;
  277. case ACPI_VARIABLE_LENGTH:
  278. /* Variable length resource, length must be at least the minimum */
  279. if (resource_length < minimum_resource_length) {
  280. goto bad_resource_length;
  281. }
  282. break;
  283. case ACPI_SMALL_VARIABLE_LENGTH:
  284. /* Small variable length resource, length can be (Min) or (Min-1) */
  285. if ((resource_length > minimum_resource_length) ||
  286. (resource_length < (minimum_resource_length - 1))) {
  287. goto bad_resource_length;
  288. }
  289. break;
  290. default:
  291. /* Shouldn't happen (because of validation earlier), but be sure */
  292. goto invalid_resource;
  293. }
  294. aml_resource = ACPI_CAST_PTR(union aml_resource, aml);
  295. if (resource_type == ACPI_RESOURCE_NAME_SERIAL_BUS) {
  296. /* Validate the bus_type field */
  297. if ((aml_resource->common_serial_bus.type == 0) ||
  298. (aml_resource->common_serial_bus.type >
  299. AML_RESOURCE_MAX_SERIALBUSTYPE)) {
  300. if (walk_state) {
  301. ACPI_ERROR((AE_INFO,
  302. "Invalid/unsupported SerialBus resource descriptor: BusType 0x%2.2X",
  303. aml_resource->common_serial_bus.
  304. type));
  305. }
  306. return (AE_AML_INVALID_RESOURCE_TYPE);
  307. }
  308. }
  309. /* Optionally return the resource table index */
  310. if (return_index) {
  311. *return_index = resource_index;
  312. }
  313. return (AE_OK);
  314. invalid_resource:
  315. if (walk_state) {
  316. ACPI_ERROR((AE_INFO,
  317. "Invalid/unsupported resource descriptor: Type 0x%2.2X",
  318. resource_type));
  319. }
  320. return (AE_AML_INVALID_RESOURCE_TYPE);
  321. bad_resource_length:
  322. if (walk_state) {
  323. ACPI_ERROR((AE_INFO,
  324. "Invalid resource descriptor length: Type "
  325. "0x%2.2X, Length 0x%4.4X, MinLength 0x%4.4X",
  326. resource_type, resource_length,
  327. minimum_resource_length));
  328. }
  329. return (AE_AML_BAD_RESOURCE_LENGTH);
  330. }
  331. /*******************************************************************************
  332. *
  333. * FUNCTION: acpi_ut_get_resource_type
  334. *
  335. * PARAMETERS: aml - Pointer to the raw AML resource descriptor
  336. *
  337. * RETURN: The Resource Type with no extraneous bits (except the
  338. * Large/Small descriptor bit -- this is left alone)
  339. *
  340. * DESCRIPTION: Extract the Resource Type/Name from the first byte of
  341. * a resource descriptor.
  342. *
  343. ******************************************************************************/
  344. u8 acpi_ut_get_resource_type(void *aml)
  345. {
  346. ACPI_FUNCTION_ENTRY();
  347. /*
  348. * Byte 0 contains the descriptor name (Resource Type)
  349. * Examine the large/small bit in the resource header
  350. */
  351. if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) {
  352. /* Large Resource Type -- bits 6:0 contain the name */
  353. return (ACPI_GET8(aml));
  354. } else {
  355. /* Small Resource Type -- bits 6:3 contain the name */
  356. return ((u8) (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_SMALL_MASK));
  357. }
  358. }
  359. /*******************************************************************************
  360. *
  361. * FUNCTION: acpi_ut_get_resource_length
  362. *
  363. * PARAMETERS: aml - Pointer to the raw AML resource descriptor
  364. *
  365. * RETURN: Byte Length
  366. *
  367. * DESCRIPTION: Get the "Resource Length" of a raw AML descriptor. By
  368. * definition, this does not include the size of the descriptor
  369. * header or the length field itself.
  370. *
  371. ******************************************************************************/
  372. u16 acpi_ut_get_resource_length(void *aml)
  373. {
  374. acpi_rs_length resource_length;
  375. ACPI_FUNCTION_ENTRY();
  376. /*
  377. * Byte 0 contains the descriptor name (Resource Type)
  378. * Examine the large/small bit in the resource header
  379. */
  380. if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) {
  381. /* Large Resource type -- bytes 1-2 contain the 16-bit length */
  382. ACPI_MOVE_16_TO_16(&resource_length, ACPI_ADD_PTR(u8, aml, 1));
  383. } else {
  384. /* Small Resource type -- bits 2:0 of byte 0 contain the length */
  385. resource_length = (u16) (ACPI_GET8(aml) &
  386. ACPI_RESOURCE_NAME_SMALL_LENGTH_MASK);
  387. }
  388. return (resource_length);
  389. }
  390. /*******************************************************************************
  391. *
  392. * FUNCTION: acpi_ut_get_resource_header_length
  393. *
  394. * PARAMETERS: aml - Pointer to the raw AML resource descriptor
  395. *
  396. * RETURN: Length of the AML header (depends on large/small descriptor)
  397. *
  398. * DESCRIPTION: Get the length of the header for this resource.
  399. *
  400. ******************************************************************************/
  401. u8 acpi_ut_get_resource_header_length(void *aml)
  402. {
  403. ACPI_FUNCTION_ENTRY();
  404. /* Examine the large/small bit in the resource header */
  405. if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) {
  406. return (sizeof(struct aml_resource_large_header));
  407. } else {
  408. return (sizeof(struct aml_resource_small_header));
  409. }
  410. }
  411. /*******************************************************************************
  412. *
  413. * FUNCTION: acpi_ut_get_descriptor_length
  414. *
  415. * PARAMETERS: aml - Pointer to the raw AML resource descriptor
  416. *
  417. * RETURN: Byte length
  418. *
  419. * DESCRIPTION: Get the total byte length of a raw AML descriptor, including the
  420. * length of the descriptor header and the length field itself.
  421. * Used to walk descriptor lists.
  422. *
  423. ******************************************************************************/
  424. u32 acpi_ut_get_descriptor_length(void *aml)
  425. {
  426. ACPI_FUNCTION_ENTRY();
  427. /*
  428. * Get the Resource Length (does not include header length) and add
  429. * the header length (depends on if this is a small or large resource)
  430. */
  431. return (acpi_ut_get_resource_length(aml) +
  432. acpi_ut_get_resource_header_length(aml));
  433. }
  434. /*******************************************************************************
  435. *
  436. * FUNCTION: acpi_ut_get_resource_end_tag
  437. *
  438. * PARAMETERS: obj_desc - The resource template buffer object
  439. * end_tag - Where the pointer to the end_tag is returned
  440. *
  441. * RETURN: Status, pointer to the end tag
  442. *
  443. * DESCRIPTION: Find the end_tag resource descriptor in an AML resource template
  444. * Note: allows a buffer length of zero.
  445. *
  446. ******************************************************************************/
  447. acpi_status
  448. acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc, u8 **end_tag)
  449. {
  450. acpi_status status;
  451. ACPI_FUNCTION_TRACE(ut_get_resource_end_tag);
  452. /* Allow a buffer length of zero */
  453. if (!obj_desc->buffer.length) {
  454. *end_tag = obj_desc->buffer.pointer;
  455. return_ACPI_STATUS(AE_OK);
  456. }
  457. /* Validate the template and get a pointer to the end_tag */
  458. status = acpi_ut_walk_aml_resources(NULL, obj_desc->buffer.pointer,
  459. obj_desc->buffer.length, NULL,
  460. (void **)end_tag);
  461. return_ACPI_STATUS(status);
  462. }