errata_report.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /*
  2. * Copyright (c) 2017-2023, Arm Limited and Contributors. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. /* Runtime firmware routines to report errata status for the current CPU. */
  7. #include <assert.h>
  8. #include <stdbool.h>
  9. #include <arch_helpers.h>
  10. #include <common/debug.h>
  11. #include <lib/cpus/cpu_ops.h>
  12. #include <lib/cpus/errata.h>
  13. #include <lib/el3_runtime/cpu_data.h>
  14. #include <lib/spinlock.h>
  15. #ifdef IMAGE_BL1
  16. # define BL_STRING "BL1"
  17. #elif defined(__aarch64__) && defined(IMAGE_BL31)
  18. # define BL_STRING "BL31"
  19. #elif !defined(__aarch64__) && defined(IMAGE_BL32)
  20. # define BL_STRING "BL32"
  21. #elif defined(IMAGE_BL2) && RESET_TO_BL2
  22. # define BL_STRING "BL2"
  23. #else
  24. # error This image should not be printing errata status
  25. #endif
  26. /* Errata format: BL stage, CPU, errata ID, message */
  27. #define ERRATA_FORMAT "%s: %s: CPU workaround for %s was %s\n"
  28. #define CVE_FORMAT "%s: %s: CPU workaround for CVE %u_%u was %s\n"
  29. #define ERRATUM_FORMAT "%s: %s: CPU workaround for erratum %u was %s\n"
  30. static __unused void print_status(int status, char *cpu_str, uint16_t cve, uint32_t id)
  31. {
  32. if (status == ERRATA_MISSING) {
  33. if (cve) {
  34. WARN(CVE_FORMAT, BL_STRING, cpu_str, cve, id, "missing!");
  35. } else {
  36. WARN(ERRATUM_FORMAT, BL_STRING, cpu_str, id, "missing!");
  37. }
  38. } else if (status == ERRATA_APPLIES) {
  39. if (cve) {
  40. INFO(CVE_FORMAT, BL_STRING, cpu_str, cve, id, "applied");
  41. } else {
  42. INFO(ERRATUM_FORMAT, BL_STRING, cpu_str, id, "applied");
  43. }
  44. } else {
  45. if (cve) {
  46. VERBOSE(CVE_FORMAT, BL_STRING, cpu_str, cve, id, "not applied");
  47. } else {
  48. VERBOSE(ERRATUM_FORMAT, BL_STRING, cpu_str, id, "not applied");
  49. }
  50. }
  51. }
  52. #if !REPORT_ERRATA
  53. void print_errata_status(void) {}
  54. #else /* !REPORT_ERRATA */
  55. /*
  56. * New errata status message printer
  57. * The order checking function is hidden behind the FEATURE_DETECTION flag to
  58. * save space. This functionality is only useful on development and platform
  59. * bringup builds, when FEATURE_DETECTION should be used anyway
  60. */
  61. void __unused generic_errata_report(void)
  62. {
  63. struct cpu_ops *cpu_ops = get_cpu_ops_ptr();
  64. struct erratum_entry *entry = cpu_ops->errata_list_start;
  65. struct erratum_entry *end = cpu_ops->errata_list_end;
  66. long rev_var = cpu_get_rev_var();
  67. #if FEATURE_DETECTION
  68. uint32_t last_erratum_id = 0;
  69. uint16_t last_cve_yr = 0;
  70. bool check_cve = false;
  71. bool failed = false;
  72. #endif /* FEATURE_DETECTION */
  73. for (; entry != end; entry += 1) {
  74. uint64_t status = entry->check_func(rev_var);
  75. assert(entry->id != 0);
  76. /*
  77. * Errata workaround has not been compiled in. If the errata
  78. * would have applied had it been compiled in, print its status
  79. * as missing.
  80. */
  81. if (status == ERRATA_APPLIES && entry->chosen == 0) {
  82. status = ERRATA_MISSING;
  83. }
  84. print_status(status, cpu_ops->cpu_str, entry->cve, entry->id);
  85. #if FEATURE_DETECTION
  86. if (entry->cve) {
  87. if (last_cve_yr > entry->cve ||
  88. (last_cve_yr == entry->cve && last_erratum_id >= entry->id)) {
  89. ERROR("CVE %u_%u was out of order!\n",
  90. entry->cve, entry->id);
  91. failed = true;
  92. }
  93. check_cve = true;
  94. last_cve_yr = entry->cve;
  95. } else {
  96. if (last_erratum_id >= entry->id || check_cve) {
  97. ERROR("Erratum %u was out of order!\n",
  98. entry->id);
  99. failed = true;
  100. }
  101. }
  102. last_erratum_id = entry->id;
  103. #endif /* FEATURE_DETECTION */
  104. }
  105. #if FEATURE_DETECTION
  106. /*
  107. * enforce errata and CVEs are in ascending order and that CVEs are
  108. * after errata
  109. */
  110. assert(!failed);
  111. #endif /* FEATURE_DETECTION */
  112. }
  113. /*
  114. * Returns whether errata needs to be reported. Passed arguments are private to
  115. * a CPU type.
  116. */
  117. static __unused int errata_needs_reporting(spinlock_t *lock, uint32_t *reported)
  118. {
  119. bool report_now;
  120. /* If already reported, return false. */
  121. if (*reported != 0U)
  122. return 0;
  123. /*
  124. * Acquire lock. Determine whether status needs reporting, and then mark
  125. * report status to true.
  126. */
  127. spin_lock(lock);
  128. report_now = (*reported == 0U);
  129. if (report_now)
  130. *reported = 1;
  131. spin_unlock(lock);
  132. return report_now;
  133. }
  134. /*
  135. * Function to print errata status for the calling CPU (and others of the same
  136. * type). Must be called only:
  137. * - when MMU and data caches are enabled;
  138. * - after cpu_ops have been initialized in per-CPU data.
  139. */
  140. void print_errata_status(void)
  141. {
  142. struct cpu_ops *cpu_ops;
  143. #ifdef IMAGE_BL1
  144. /*
  145. * BL1 doesn't have per-CPU data. So retrieve the CPU operations
  146. * directly.
  147. */
  148. cpu_ops = get_cpu_ops_ptr();
  149. if (cpu_ops->errata_func != NULL) {
  150. cpu_ops->errata_func();
  151. }
  152. #else /* IMAGE_BL1 */
  153. cpu_ops = (void *) get_cpu_data(cpu_ops_ptr);
  154. assert(cpu_ops != NULL);
  155. if (cpu_ops->errata_func == NULL) {
  156. return;
  157. }
  158. if (errata_needs_reporting(cpu_ops->errata_lock, cpu_ops->errata_reported)) {
  159. cpu_ops->errata_func();
  160. }
  161. #endif /* IMAGE_BL1 */
  162. }
  163. /*
  164. * Old errata status message printer
  165. * TODO: remove once all cpus have been converted to the new printing method
  166. */
  167. void __unused errata_print_msg(unsigned int status, const char *cpu, const char *id)
  168. {
  169. /* Errata status strings */
  170. static const char *const errata_status_str[] = {
  171. [ERRATA_NOT_APPLIES] = "not applied",
  172. [ERRATA_APPLIES] = "applied",
  173. [ERRATA_MISSING] = "missing!"
  174. };
  175. static const char *const __unused bl_str = BL_STRING;
  176. const char *msg __unused;
  177. assert(status < ARRAY_SIZE(errata_status_str));
  178. assert(cpu != NULL);
  179. assert(id != NULL);
  180. msg = errata_status_str[status];
  181. switch (status) {
  182. case ERRATA_NOT_APPLIES:
  183. VERBOSE(ERRATA_FORMAT, bl_str, cpu, id, msg);
  184. break;
  185. case ERRATA_APPLIES:
  186. INFO(ERRATA_FORMAT, bl_str, cpu, id, msg);
  187. break;
  188. case ERRATA_MISSING:
  189. WARN(ERRATA_FORMAT, bl_str, cpu, id, msg);
  190. break;
  191. default:
  192. WARN(ERRATA_FORMAT, bl_str, cpu, id, "unknown");
  193. break;
  194. }
  195. }
  196. #endif /* !REPORT_ERRATA */