1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Tests SIE with paging. 4 * 5 * Copyright 2023 IBM Corp. 6 * 7 * Authors: 8 * Nico Boehr <nrb@linux.ibm.com> 9 */ 10 #include <libcflat.h> 11 #include <vmalloc.h> 12 #include <asm/pgtable.h> 13 #include <mmu.h> 14 #include <asm/page.h> 15 #include <asm/interrupt.h> 16 #include <alloc_page.h> 17 #include <sclp.h> 18 #include <sie.h> 19 #include <snippet.h> 20 #include <snippet-exit.h> 21 #include "snippets/c/sie-dat.h" 22 23 static struct vm vm; 24 static pgd_t *guest_root; 25 26 static void test_sie_dat(void) 27 { 28 uint64_t test_page_gpa, test_page_hpa; 29 uint8_t *test_page_hva, expected_val; 30 bool contents_match; 31 32 /* guest will tell us the guest physical address of the test buffer */ 33 sie(&vm); 34 assert(snippet_is_force_exit_value(&vm)); 35 test_page_gpa = snippet_get_force_exit_value(&vm); 36 test_page_hpa = virt_to_pte_phys(guest_root, (void*)test_page_gpa); 37 test_page_hva = __va(test_page_hpa); 38 report_info("test buffer gpa=0x%lx hva=%p", test_page_gpa, test_page_hva); 39 40 /* guest will now write to the test buffer and we verify the contents */ 41 sie(&vm); 42 assert(snippet_is_force_exit(&vm)); 43 44 contents_match = true; 45 for (unsigned int i = 0; i < GUEST_TEST_PAGE_COUNT; i++) { 46 expected_val = 42 + i; 47 if (test_page_hva[i * PAGE_SIZE] != expected_val) { 48 report_fail("page %u mismatch actual_val=%x expected_val=%x", 49 i, test_page_hva[i], expected_val); 50 contents_match = false; 51 } 52 } 53 report(contents_match, "test buffer contents match"); 54 55 /* the guest will now write to an unmapped address and we check that this causes a segment translation exception */ 56 report_prefix_push("guest write to unmapped"); 57 expect_pgm_int(); 58 sie(&vm); 59 check_pgm_int_code(PGM_INT_CODE_SEGMENT_TRANSLATION); 60 report((lowcore.trans_exc_id & PAGE_MASK) == (GUEST_TOTAL_PAGE_COUNT * PAGE_SIZE), "TEID address match"); 61 report_prefix_pop(); 62 } 63 64 static void setup_guest(void) 65 { 66 extern const char SNIPPET_NAME_START(c, sie_dat)[]; 67 extern const char SNIPPET_NAME_END(c, sie_dat)[]; 68 uint64_t guest_max_addr; 69 pgd_t *root; 70 71 setup_vm(); 72 root = (pgd_t *)(stctg(1) & PAGE_MASK); 73 74 snippet_setup_guest(&vm, false); 75 76 /* allocate a region-1 table */ 77 guest_root = pgd_alloc_one(); 78 79 /* map guest memory 1:1 */ 80 guest_max_addr = GUEST_TOTAL_PAGE_COUNT * PAGE_SIZE; 81 for (uint64_t i = 0; i < guest_max_addr; i += PAGE_SIZE) 82 install_page(guest_root, virt_to_pte_phys(root, vm.guest_mem + i), (void *)i); 83 84 /* set up storage limit supression - leave mso and msl intact they are ignored anyways */ 85 vm.sblk->cpuflags |= CPUSTAT_SM; 86 87 /* set up the guest asce */ 88 vm.save_area.guest.asce = __pa(guest_root) | ASCE_DT_REGION1 | REGION_TABLE_LENGTH; 89 90 snippet_init(&vm, SNIPPET_NAME_START(c, sie_dat), 91 SNIPPET_LEN(c, sie_dat), SNIPPET_UNPACK_OFF); 92 } 93 94 int main(void) 95 { 96 report_prefix_push("sie-dat"); 97 if (!sclp_facilities.has_sief2) { 98 report_skip("SIEF2 facility unavailable"); 99 goto done; 100 } 101 102 setup_guest(); 103 test_sie_dat(); 104 sie_guest_destroy(&vm); 105 106 done: 107 report_prefix_pop(); 108 return report_summary(); 109 110 } 111