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