utresrc.c 16 KB

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