spectre_v2.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright 2018-2019 IBM Corporation.
  4. */
  5. #define __SANE_USERSPACE_TYPES__
  6. #include <sys/types.h>
  7. #include <stdint.h>
  8. #include <malloc.h>
  9. #include <unistd.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <stdio.h>
  13. #include <sys/prctl.h>
  14. #include "utils.h"
  15. #include "../pmu/event.h"
  16. extern void pattern_cache_loop(void);
  17. extern void indirect_branch_loop(void);
  18. static int do_count_loop(struct event *events, bool is_p9, s64 *miss_percent)
  19. {
  20. u64 pred, mpred;
  21. prctl(PR_TASK_PERF_EVENTS_ENABLE);
  22. if (is_p9)
  23. pattern_cache_loop();
  24. else
  25. indirect_branch_loop();
  26. prctl(PR_TASK_PERF_EVENTS_DISABLE);
  27. event_read(&events[0]);
  28. event_read(&events[1]);
  29. // We could scale all the events by running/enabled but we're lazy
  30. // As long as the PMU is uncontended they should all run
  31. FAIL_IF(events[0].result.running != events[0].result.enabled);
  32. FAIL_IF(events[1].result.running != events[1].result.enabled);
  33. pred = events[0].result.value;
  34. mpred = events[1].result.value;
  35. if (is_p9) {
  36. event_read(&events[2]);
  37. event_read(&events[3]);
  38. FAIL_IF(events[2].result.running != events[2].result.enabled);
  39. FAIL_IF(events[3].result.running != events[3].result.enabled);
  40. pred += events[2].result.value;
  41. mpred += events[3].result.value;
  42. }
  43. *miss_percent = 100 * mpred / pred;
  44. return 0;
  45. }
  46. static void setup_event(struct event *e, u64 config, char *name)
  47. {
  48. event_init_named(e, config, name);
  49. e->attr.disabled = 1;
  50. e->attr.exclude_kernel = 1;
  51. e->attr.exclude_hv = 1;
  52. e->attr.exclude_idle = 1;
  53. }
  54. enum spectre_v2_state {
  55. VULNERABLE = 0,
  56. UNKNOWN = 1, // Works with FAIL_IF()
  57. NOT_AFFECTED,
  58. BRANCH_SERIALISATION,
  59. COUNT_CACHE_DISABLED,
  60. COUNT_CACHE_FLUSH_SW,
  61. COUNT_CACHE_FLUSH_HW,
  62. BTB_FLUSH,
  63. };
  64. static enum spectre_v2_state get_sysfs_state(void)
  65. {
  66. enum spectre_v2_state state = UNKNOWN;
  67. char buf[256];
  68. int len;
  69. memset(buf, 0, sizeof(buf));
  70. FAIL_IF(read_sysfs_file("devices/system/cpu/vulnerabilities/spectre_v2", buf, sizeof(buf)));
  71. // Make sure it's NULL terminated
  72. buf[sizeof(buf) - 1] = '\0';
  73. // Trim the trailing newline
  74. len = strlen(buf);
  75. FAIL_IF(len < 1);
  76. buf[len - 1] = '\0';
  77. printf("sysfs reports: '%s'\n", buf);
  78. // Order matters
  79. if (strstr(buf, "Vulnerable"))
  80. state = VULNERABLE;
  81. else if (strstr(buf, "Not affected"))
  82. state = NOT_AFFECTED;
  83. else if (strstr(buf, "Indirect branch serialisation (kernel only)"))
  84. state = BRANCH_SERIALISATION;
  85. else if (strstr(buf, "Indirect branch cache disabled"))
  86. state = COUNT_CACHE_DISABLED;
  87. else if (strstr(buf, "Software count cache flush (hardware accelerated)"))
  88. state = COUNT_CACHE_FLUSH_HW;
  89. else if (strstr(buf, "Software count cache flush"))
  90. state = COUNT_CACHE_FLUSH_SW;
  91. else if (strstr(buf, "Branch predictor state flush"))
  92. state = BTB_FLUSH;
  93. return state;
  94. }
  95. #define PM_BR_PRED_CCACHE 0x040a4 // P8 + P9
  96. #define PM_BR_MPRED_CCACHE 0x040ac // P8 + P9
  97. #define PM_BR_PRED_PCACHE 0x048a0 // P9 only
  98. #define PM_BR_MPRED_PCACHE 0x048b0 // P9 only
  99. int spectre_v2_test(void)
  100. {
  101. enum spectre_v2_state state;
  102. struct event events[4];
  103. s64 miss_percent;
  104. bool is_p9;
  105. // The PMU events we use only work on Power8 or later
  106. SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_2_07));
  107. state = get_sysfs_state();
  108. if (state == UNKNOWN) {
  109. printf("Error: couldn't determine spectre_v2 mitigation state?\n");
  110. return -1;
  111. }
  112. memset(events, 0, sizeof(events));
  113. setup_event(&events[0], PM_BR_PRED_CCACHE, "PM_BR_PRED_CCACHE");
  114. setup_event(&events[1], PM_BR_MPRED_CCACHE, "PM_BR_MPRED_CCACHE");
  115. FAIL_IF(event_open(&events[0]));
  116. FAIL_IF(event_open_with_group(&events[1], events[0].fd) == -1);
  117. is_p9 = ((mfspr(SPRN_PVR) >> 16) & 0xFFFF) == 0x4e;
  118. if (is_p9) {
  119. // Count pattern cache too
  120. setup_event(&events[2], PM_BR_PRED_PCACHE, "PM_BR_PRED_PCACHE");
  121. setup_event(&events[3], PM_BR_MPRED_PCACHE, "PM_BR_MPRED_PCACHE");
  122. FAIL_IF(event_open_with_group(&events[2], events[0].fd) == -1);
  123. FAIL_IF(event_open_with_group(&events[3], events[0].fd) == -1);
  124. }
  125. FAIL_IF(do_count_loop(events, is_p9, &miss_percent));
  126. event_report_justified(&events[0], 18, 10);
  127. event_report_justified(&events[1], 18, 10);
  128. event_close(&events[0]);
  129. event_close(&events[1]);
  130. if (is_p9) {
  131. event_report_justified(&events[2], 18, 10);
  132. event_report_justified(&events[3], 18, 10);
  133. event_close(&events[2]);
  134. event_close(&events[3]);
  135. }
  136. printf("Miss percent %lld %%\n", miss_percent);
  137. switch (state) {
  138. case VULNERABLE:
  139. case NOT_AFFECTED:
  140. case COUNT_CACHE_FLUSH_SW:
  141. case COUNT_CACHE_FLUSH_HW:
  142. // These should all not affect userspace branch prediction
  143. if (miss_percent > 15) {
  144. if (miss_percent > 95) {
  145. /*
  146. * Such a mismatch may be caused by a system being unaware
  147. * the count cache is disabled. This may be to enable
  148. * guest migration between hosts with different settings.
  149. * Return skip code to avoid detecting this as an error.
  150. * We are not vulnerable and reporting otherwise, so
  151. * missing such a mismatch is safe.
  152. */
  153. printf("Branch misses > 95%% unexpected in this configuration.\n");
  154. printf("Count cache likely disabled without Linux knowing.\n");
  155. if (state == COUNT_CACHE_FLUSH_SW)
  156. printf("WARNING: Kernel performing unnecessary flushes.\n");
  157. return 4;
  158. }
  159. printf("Branch misses > 15%% unexpected in this configuration!\n");
  160. printf("Possible mismatch between reported & actual mitigation\n");
  161. return 1;
  162. }
  163. break;
  164. case BRANCH_SERIALISATION:
  165. // This seems to affect userspace branch prediction a bit?
  166. if (miss_percent > 25) {
  167. printf("Branch misses > 25%% unexpected in this configuration!\n");
  168. printf("Possible mismatch between reported & actual mitigation\n");
  169. return 1;
  170. }
  171. break;
  172. case COUNT_CACHE_DISABLED:
  173. if (miss_percent < 95) {
  174. printf("Branch misses < 95%% unexpected in this configuration!\n");
  175. printf("Possible mismatch between reported & actual mitigation\n");
  176. return 1;
  177. }
  178. break;
  179. case UNKNOWN:
  180. case BTB_FLUSH:
  181. printf("Not sure!\n");
  182. return 1;
  183. }
  184. printf("OK - Measured branch prediction rates match reported spectre v2 mitigation.\n");
  185. return 0;
  186. }
  187. int main(int argc, char *argv[])
  188. {
  189. return test_harness(spectre_v2_test, "spectre_v2");
  190. }