1 /* 2 * Test sPAPR hypervisor calls (aka. h-calls) 3 * 4 * Copyright 2016 Thomas Huth, Red Hat Inc. 5 * 6 * This work is licensed under the terms of the GNU LGPL, version 2. 7 */ 8 #include <libcflat.h> 9 #include <util.h> 10 #include <alloc.h> 11 #include <asm/hcall.h> 12 13 #define PAGE_SIZE 4096 14 15 #define H_ZERO_PAGE (1UL << (63-48)) 16 #define H_COPY_PAGE (1UL << (63-49)) 17 18 #define mfspr(nr) ({ \ 19 uint64_t ret; \ 20 asm volatile("mfspr %0,%1" : "=r"(ret) : "i"(nr)); \ 21 ret; \ 22 }) 23 24 #define SPR_SPRG0 0x110 25 26 /** 27 * Test the H_SET_SPRG0 h-call by setting some values and checking whether 28 * the SPRG0 register contains the correct values afterwards 29 */ 30 static void test_h_set_sprg0(int argc, char **argv) 31 { 32 uint64_t sprg0, sprg0_orig; 33 int rc; 34 35 if (argc > 1) 36 report_abort("Unsupported argument: '%s'", argv[1]); 37 38 sprg0_orig = mfspr(SPR_SPRG0); 39 40 rc = hcall(H_SET_SPRG0, 0xcafebabedeadbeefULL); 41 sprg0 = mfspr(SPR_SPRG0); 42 report(rc == H_SUCCESS && sprg0 == 0xcafebabedeadbeefULL, 43 "sprg0 = 0xcafebabedeadbeef"); 44 45 rc = hcall(H_SET_SPRG0, 0xaaaaaaaa55555555ULL); 46 sprg0 = mfspr(SPR_SPRG0); 47 report(rc == H_SUCCESS && sprg0 == 0xaaaaaaaa55555555ULL, 48 "sprg0 = 0xaaaaaaaa55555555"); 49 50 rc = hcall(H_SET_SPRG0, sprg0_orig); 51 sprg0 = mfspr(SPR_SPRG0); 52 report(rc == H_SUCCESS && sprg0 == sprg0_orig, "sprg0 = %#" PRIx64, 53 sprg0_orig); 54 } 55 56 /** 57 * Test the H_PAGE_INIT h-call by using it to clear and to copy a page, and 58 * by checking for the correct values in the destination page afterwards 59 */ 60 static void test_h_page_init(int argc, char **argv) 61 { 62 u8 *dst, *src; 63 int rc; 64 65 if (argc > 1) 66 report_abort("Unsupported argument: '%s'", argv[1]); 67 68 dst = memalign(PAGE_SIZE, PAGE_SIZE); 69 src = memalign(PAGE_SIZE, PAGE_SIZE); 70 if (!dst || !src) 71 report_abort("Failed to alloc memory"); 72 73 memset(dst, 0xaa, PAGE_SIZE); 74 rc = hcall(H_PAGE_INIT, H_ZERO_PAGE, dst, src); 75 report(rc == H_SUCCESS && *(uint64_t *)dst == 0, "h_zero_page"); 76 77 *(uint64_t*)src = 0xbeefc0dedeadcafeULL; 78 rc = hcall(H_PAGE_INIT, H_COPY_PAGE, dst, src); 79 report(rc == H_SUCCESS && *(uint64_t *)dst == 0xbeefc0dedeadcafeULL, 80 "h_copy_page"); 81 82 *(uint64_t*)src = 0x9abcdef012345678ULL; 83 rc = hcall(H_PAGE_INIT, H_COPY_PAGE|H_ZERO_PAGE, dst, src); 84 report(rc == H_SUCCESS && *(uint64_t *)dst == 0x9abcdef012345678ULL, 85 "h_copy_page+h_zero_page"); 86 87 rc = hcall(H_PAGE_INIT, H_ZERO_PAGE, dst + 0x123, src); 88 report(rc == H_PARAMETER, "h_zero_page unaligned dst"); 89 90 rc = hcall(H_PAGE_INIT, H_COPY_PAGE, dst, src + 0x123); 91 report(rc == H_PARAMETER, "h_copy_page unaligned src"); 92 } 93 94 static int h_random(uint64_t *val) 95 { 96 register uint64_t r3 asm("r3") = H_RANDOM; 97 register uint64_t r4 asm("r4"); 98 99 asm volatile (" sc 1 " : "+r"(r3), "=r"(r4) : 100 : "r0", "r5", "r6", "r7", "r8", "r9", "r10", 101 "r11", "r12", "xer", "ctr", "cc"); 102 *val = r4; 103 104 return r3; 105 } 106 107 /** 108 * Test H_RANDOM by calling it a couple of times to check whether all bit 109 * positions really toggle (there should be no "stuck" bits in the output) 110 */ 111 static void test_h_random(int argc, char **argv) 112 { 113 uint64_t rval, val0, val1; 114 int rc, i; 115 116 if (argc > 1) 117 report_abort("Unsupported argument: '%s'", argv[1]); 118 119 /* H_RANDOM is optional - so check for sane return values first */ 120 rc = h_random(&rval); 121 if (rc == H_FUNCTION) { 122 report_skip("h-call is not available"); 123 return; 124 } 125 report(rc == H_SUCCESS, "h-call can be used successfully"); 126 127 val0 = 0ULL; 128 val1 = ~0ULL; 129 130 i = 100; 131 do { 132 rc = h_random(&rval); 133 if (rc != H_SUCCESS) 134 break; 135 val0 |= rval; 136 val1 &= rval; 137 } while (i-- > 0 && (val0 != ~0ULL || val1 != 0ULL)); 138 139 report(rc == H_SUCCESS && val0 == ~0ULL && val1 == 0, "no stuck bits"); 140 } 141 142 struct { 143 const char *name; 144 void (*func)(int argc, char **argv); 145 } hctests[] = { 146 { "h_set_sprg0", test_h_set_sprg0 }, 147 { "h_page_init", test_h_page_init }, 148 { "h_random", test_h_random }, 149 { NULL, NULL } 150 }; 151 152 int main(int argc, char **argv) 153 { 154 int all = 0; 155 int i; 156 157 report_prefix_push("hypercall"); 158 159 if (argc < 2 || (argc == 2 && !strcmp(argv[1], "all"))) 160 all = 1; 161 162 for (i = 0; hctests[i].name != NULL; i++) { 163 report_prefix_push(hctests[i].name); 164 if (all || strcmp(argv[1], hctests[i].name) == 0) { 165 hctests[i].func(argc-1, &argv[1]); 166 } 167 report_prefix_pop(); 168 } 169 170 return report_summary(); 171 } 172