1 #include <libcflat.h> 2 #include <asm/asm-offsets.h> 3 #include <asm-generic/barrier.h> 4 #include <asm/pgtable.h> 5 #include <mmu.h> 6 #include <asm/page.h> 7 #include <asm/facility.h> 8 #include <asm/mem.h> 9 #include <alloc_page.h> 10 #include <vm.h> 11 #include <sclp.h> 12 #include <sie.h> 13 14 static u8 *guest; 15 static u8 *guest_instr; 16 static struct vm vm; 17 18 static uint8_t *src; 19 static uint8_t *dst; 20 static uint8_t *cmp; 21 22 extern const char _binary_s390x_snippets_c_mvpg_snippet_gbin_start[]; 23 extern const char _binary_s390x_snippets_c_mvpg_snippet_gbin_end[]; 24 int binary_size; 25 26 static void sie(struct vm *vm) 27 { 28 /* Reset icptcode so we don't trip over it below */ 29 vm->sblk->icptcode = 0; 30 31 while (vm->sblk->icptcode == 0) { 32 sie64a(vm->sblk, &vm->save_area); 33 assert(vm->sblk->icptcode != ICPT_VALIDITY); 34 } 35 vm->save_area.guest.grs[14] = vm->sblk->gg14; 36 vm->save_area.guest.grs[15] = vm->sblk->gg15; 37 } 38 39 static void test_mvpg_pei(void) 40 { 41 uint64_t **pei_dst = (uint64_t **)((uintptr_t) vm.sblk + 0xc0); 42 uint64_t **pei_src = (uint64_t **)((uintptr_t) vm.sblk + 0xc8); 43 44 report_prefix_push("pei"); 45 46 report_prefix_push("src"); 47 memset(dst, 0, PAGE_SIZE); 48 protect_page(src, PAGE_ENTRY_I); 49 sie(&vm); 50 report(vm.sblk->icptcode == ICPT_PARTEXEC, "Partial execution"); 51 report((uintptr_t)**pei_src == (uintptr_t)src + PAGE_ENTRY_I, "PEI_SRC correct"); 52 report((uintptr_t)**pei_dst == (uintptr_t)dst, "PEI_DST correct"); 53 unprotect_page(src, PAGE_ENTRY_I); 54 report(!memcmp(cmp, dst, PAGE_SIZE), "Destination intact"); 55 /* 56 * We need to execute the diag44 which is used as a blocker 57 * behind the mvpg. It makes sure we fail the tests above if 58 * the mvpg wouldn't have intercepted. 59 */ 60 sie(&vm); 61 /* Make sure we intercepted for the diag44 and nothing else */ 62 assert(vm.sblk->icptcode == ICPT_INST && 63 vm.sblk->ipa == 0x8300 && vm.sblk->ipb == 0x440000); 64 report_prefix_pop(); 65 66 /* Clear PEI data for next check */ 67 report_prefix_push("dst"); 68 memset((uint64_t *)((uintptr_t) vm.sblk + 0xc0), 0, 16); 69 memset(dst, 0, PAGE_SIZE); 70 protect_page(dst, PAGE_ENTRY_I); 71 sie(&vm); 72 report(vm.sblk->icptcode == ICPT_PARTEXEC, "Partial execution"); 73 report((uintptr_t)**pei_src == (uintptr_t)src, "PEI_SRC correct"); 74 report((uintptr_t)**pei_dst == (uintptr_t)dst + PAGE_ENTRY_I, "PEI_DST correct"); 75 /* Needed for the memcmp and general cleanup */ 76 unprotect_page(dst, PAGE_ENTRY_I); 77 report(!memcmp(cmp, dst, PAGE_SIZE), "Destination intact"); 78 report_prefix_pop(); 79 80 report_prefix_pop(); 81 } 82 83 static void test_mvpg(void) 84 { 85 int binary_size = ((uintptr_t)_binary_s390x_snippets_c_mvpg_snippet_gbin_end - 86 (uintptr_t)_binary_s390x_snippets_c_mvpg_snippet_gbin_start); 87 88 memcpy(guest, _binary_s390x_snippets_c_mvpg_snippet_gbin_start, binary_size); 89 memset(src, 0x42, PAGE_SIZE); 90 memset(dst, 0x43, PAGE_SIZE); 91 sie(&vm); 92 report(!memcmp(src, dst, PAGE_SIZE) && *dst == 0x42, "Page moved"); 93 } 94 95 static void setup_guest(void) 96 { 97 setup_vm(); 98 99 /* Allocate 1MB as guest memory */ 100 guest = alloc_pages(8); 101 /* The first two pages are the lowcore */ 102 guest_instr = guest + PAGE_SIZE * 2; 103 104 vm.sblk = alloc_page(); 105 106 vm.sblk->cpuflags = CPUSTAT_ZARCH | CPUSTAT_RUNNING; 107 vm.sblk->prefix = 0; 108 /* 109 * Pageable guest with the same ASCE as the test programm, but 110 * the guest memory 0x0 is offset to start at the allocated 111 * guest pages and end after 1MB. 112 * 113 * It's not pretty but faster and easier than managing guest ASCEs. 114 */ 115 vm.sblk->mso = (u64)guest; 116 vm.sblk->msl = (u64)guest; 117 vm.sblk->ihcpu = 0xffff; 118 119 vm.sblk->crycbd = (uint64_t)alloc_page(); 120 121 vm.sblk->gpsw.addr = PAGE_SIZE * 4; 122 vm.sblk->gpsw.mask = 0x0000000180000000ULL; 123 vm.sblk->ictl = ICTL_OPEREXC | ICTL_PINT; 124 /* Enable MVPG interpretation as we want to test KVM and not ourselves */ 125 vm.sblk->eca = ECA_MVPGI; 126 127 src = guest + PAGE_SIZE * 6; 128 dst = guest + PAGE_SIZE * 5; 129 cmp = alloc_page(); 130 memset(cmp, 0, PAGE_SIZE); 131 } 132 133 int main(void) 134 { 135 report_prefix_push("mvpg-sie"); 136 if (!sclp_facilities.has_sief2) { 137 report_skip("SIEF2 facility unavailable"); 138 goto done; 139 } 140 141 setup_guest(); 142 test_mvpg(); 143 test_mvpg_pei(); 144 145 done: 146 report_prefix_pop(); 147 return report_summary(); 148 149 } 150