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