1 /* 2 * Transactional Memory Unit Tests 3 * 4 * Copyright 2016 Suraj Jitindar Singh, IBM. 5 * 6 * This work is licensed under the terms of the GNU LGPL, version 2. 7 */ 8 #include <libcflat.h> 9 #include <asm/hcall.h> 10 #include <asm/processor.h> 11 #include <asm/time.h> 12 #include <asm/handlers.h> 13 #include <asm/smp.h> 14 #include <asm/setup.h> 15 #include <devicetree.h> 16 17 /* Check "ibm,pa-features" property of a CPU node for the TM flag */ 18 static void cpu_has_tm(int fdtnode, u64 regval __unused, void *ptr) 19 { 20 const struct fdt_property *prop; 21 int plen; 22 23 prop = fdt_get_property(dt_fdt(), fdtnode, "ibm,pa-features", &plen); 24 if (!prop) /* No features means TM is also not available */ 25 return; 26 /* Sanity check for the property layout (first two bytes are header) */ 27 assert(plen >= 8 && prop->data[1] == 0 && prop->data[0] <= plen - 2); 28 29 /* 30 * The "Transactional Memory Category Support" flags are at byte 31 * offset 22 and 23 of the attribute type 0, so when adding the 32 * two bytes for the header, we've got to look at offset 24 for 33 * the TM support bit. 34 */ 35 if (prop->data[0] >= 24 && (prop->data[24] & 0x80) != 0) 36 *(int *)ptr += 1; 37 } 38 39 /* Check amount of CPUs nodes that have the TM flag */ 40 static int count_cpus_with_tm(void) 41 { 42 int ret; 43 int available = 0; 44 45 ret = dt_for_each_cpu_node(cpu_has_tm, &available); 46 if (ret < 0) 47 return ret; 48 49 return available; 50 } 51 52 /* 53 * Enable transactional memory 54 * Returns: FALSE - Failure 55 * TRUE - Success 56 */ 57 static bool enable_tm(void) 58 { 59 uint64_t msr = 0; 60 61 asm volatile ("mfmsr %[msr]" : [msr] "=r" (msr)); 62 63 msr |= (((uint64_t) 1) << 32); 64 65 asm volatile ("mtmsrd %[msr]\n\t" 66 "mfmsr %[msr]" : [msr] "+r" (msr)); 67 68 return !!(msr & (((uint64_t) 1) << 32)); 69 } 70 71 /* 72 * Test H_CEDE call while transactional memory transaction is suspended 73 * 74 * WARNING: This tests for a known vulnerability in which the host may go down. 75 * Probably best not to run this if your host going down is going to cause 76 * problems. 77 * 78 * If the test passes then your kernel probably has the necessary patch. 79 * If the test fails then the H_CEDE call was unsuccessful and the 80 * vulnerability wasn't tested. 81 * If the test hits the vulnerability then it will never complete or report and 82 * the qemu process will block indefinitely. RCU stalls will be detected on the 83 * cpu and any process scheduled on the lost cpu will also block indefinitely. 84 */ 85 static void test_h_cede_tm(int argc, char **argv) 86 { 87 int i; 88 89 if (argc > 2) 90 report_abort("Unsupported argument: '%s'", argv[2]); 91 92 if (!start_all_cpus(halt)) 93 report_abort("Failed to start secondary cpus"); 94 95 if (!enable_tm()) 96 report_abort("Failed to enable tm"); 97 98 /* 99 * Begin a transaction and guarantee we are in the suspend state 100 * before continuing 101 */ 102 asm volatile ("1: .long 0x7c00051d\n\t" /* tbegin. */ 103 "beq 2f\n\t" 104 ".long 0x7c0005dd\n\t" /* tsuspend. */ 105 "2: .long 0x7c00059c\n\t" /* tcheck cr0 */ 106 "bf 2,1b" : : : "cr0"); 107 108 for (i = 0; i < 500; i++) { 109 msleep(10); 110 mdelay(5); 111 } 112 113 report(i == 500, "H_CEDE TM"); 114 } 115 116 struct { 117 const char *name; 118 void (*func)(int argc, char **argv); 119 } hctests[] = { 120 { "h_cede_tm", test_h_cede_tm }, 121 { NULL, NULL } 122 }; 123 124 int main(int argc, char **argv) 125 { 126 bool all; 127 int i, cpus_with_tm; 128 129 report_prefix_push("tm"); 130 131 cpus_with_tm = count_cpus_with_tm(); 132 if (cpus_with_tm == 0) { 133 report_skip("TM is not available"); 134 goto done; 135 } 136 /* kvm-unit-tests can limit number of CPUs present */ 137 /* KVM does not report TM in secondary threads in POWER9 */ 138 report_kfail(host_is_kvm, cpus_with_tm >= nr_cpus_present, 139 "TM available in all 'ibm,pa-features' properties"); 140 141 all = argc == 1 || !strcmp(argv[1], "all"); 142 143 for (i = 0; hctests[i].name != NULL; i++) { 144 if (all || strcmp(argv[1], hctests[i].name) == 0) { 145 report_prefix_push(hctests[i].name); 146 hctests[i].func(argc, argv); 147 report_prefix_pop(); 148 } 149 } 150 151 done: 152 report_prefix_pop(); 153 return report_summary(); 154 } 155