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