12456fdf7SNico Boehr /* SPDX-License-Identifier: GPL-2.0-only */ 22456fdf7SNico Boehr /* 32456fdf7SNico Boehr * Tests SIE with paging. 42456fdf7SNico Boehr * 52456fdf7SNico Boehr * Copyright 2023 IBM Corp. 62456fdf7SNico Boehr * 72456fdf7SNico Boehr * Authors: 82456fdf7SNico Boehr * Nico Boehr <nrb@linux.ibm.com> 92456fdf7SNico Boehr */ 102456fdf7SNico Boehr #include <libcflat.h> 112456fdf7SNico Boehr #include <vmalloc.h> 122456fdf7SNico Boehr #include <asm/pgtable.h> 132456fdf7SNico Boehr #include <mmu.h> 142456fdf7SNico Boehr #include <asm/page.h> 152456fdf7SNico Boehr #include <asm/interrupt.h> 162456fdf7SNico Boehr #include <alloc_page.h> 172456fdf7SNico Boehr #include <sclp.h> 182456fdf7SNico Boehr #include <sie.h> 192456fdf7SNico Boehr #include <snippet.h> 20*37f185edSNina Schoetterl-Glausch #include <snippet-exit.h> 212456fdf7SNico Boehr #include "snippets/c/sie-dat.h" 222456fdf7SNico Boehr 232456fdf7SNico Boehr static struct vm vm; 242456fdf7SNico Boehr static pgd_t *guest_root; 252456fdf7SNico Boehr 262456fdf7SNico Boehr static void test_sie_dat(void) 272456fdf7SNico Boehr { 282456fdf7SNico Boehr uint64_t test_page_gpa, test_page_hpa; 292456fdf7SNico Boehr uint8_t *test_page_hva, expected_val; 302456fdf7SNico Boehr bool contents_match; 312456fdf7SNico Boehr 322456fdf7SNico Boehr /* guest will tell us the guest physical address of the test buffer */ 332456fdf7SNico Boehr sie(&vm); 34*37f185edSNina Schoetterl-Glausch assert(snippet_is_force_exit_value(&vm)); 35*37f185edSNina Schoetterl-Glausch test_page_gpa = snippet_get_force_exit_value(&vm); 362456fdf7SNico Boehr test_page_hpa = virt_to_pte_phys(guest_root, (void*)test_page_gpa); 372456fdf7SNico Boehr test_page_hva = __va(test_page_hpa); 382456fdf7SNico Boehr report_info("test buffer gpa=0x%lx hva=%p", test_page_gpa, test_page_hva); 392456fdf7SNico Boehr 402456fdf7SNico Boehr /* guest will now write to the test buffer and we verify the contents */ 412456fdf7SNico Boehr sie(&vm); 42*37f185edSNina Schoetterl-Glausch assert(snippet_is_force_exit(&vm)); 432456fdf7SNico Boehr 442456fdf7SNico Boehr contents_match = true; 452456fdf7SNico Boehr for (unsigned int i = 0; i < GUEST_TEST_PAGE_COUNT; i++) { 462456fdf7SNico Boehr expected_val = 42 + i; 472456fdf7SNico Boehr if (test_page_hva[i * PAGE_SIZE] != expected_val) { 482456fdf7SNico Boehr report_fail("page %u mismatch actual_val=%x expected_val=%x", 492456fdf7SNico Boehr i, test_page_hva[i], expected_val); 502456fdf7SNico Boehr contents_match = false; 512456fdf7SNico Boehr } 522456fdf7SNico Boehr } 532456fdf7SNico Boehr report(contents_match, "test buffer contents match"); 542456fdf7SNico Boehr 552456fdf7SNico Boehr /* the guest will now write to an unmapped address and we check that this causes a segment translation exception */ 562456fdf7SNico Boehr report_prefix_push("guest write to unmapped"); 572456fdf7SNico Boehr expect_pgm_int(); 582456fdf7SNico Boehr sie(&vm); 592456fdf7SNico Boehr check_pgm_int_code(PGM_INT_CODE_SEGMENT_TRANSLATION); 602456fdf7SNico Boehr report((lowcore.trans_exc_id & PAGE_MASK) == (GUEST_TOTAL_PAGE_COUNT * PAGE_SIZE), "TEID address match"); 612456fdf7SNico Boehr report_prefix_pop(); 622456fdf7SNico Boehr } 632456fdf7SNico Boehr 642456fdf7SNico Boehr static void setup_guest(void) 652456fdf7SNico Boehr { 662456fdf7SNico Boehr extern const char SNIPPET_NAME_START(c, sie_dat)[]; 672456fdf7SNico Boehr extern const char SNIPPET_NAME_END(c, sie_dat)[]; 682456fdf7SNico Boehr uint64_t guest_max_addr; 692456fdf7SNico Boehr pgd_t *root; 702456fdf7SNico Boehr 712456fdf7SNico Boehr setup_vm(); 722456fdf7SNico Boehr root = (pgd_t *)(stctg(1) & PAGE_MASK); 732456fdf7SNico Boehr 742456fdf7SNico Boehr snippet_setup_guest(&vm, false); 752456fdf7SNico Boehr 762456fdf7SNico Boehr /* allocate a region-1 table */ 772456fdf7SNico Boehr guest_root = pgd_alloc_one(); 782456fdf7SNico Boehr 792456fdf7SNico Boehr /* map guest memory 1:1 */ 802456fdf7SNico Boehr guest_max_addr = GUEST_TOTAL_PAGE_COUNT * PAGE_SIZE; 812456fdf7SNico Boehr for (uint64_t i = 0; i < guest_max_addr; i += PAGE_SIZE) 822456fdf7SNico Boehr install_page(guest_root, virt_to_pte_phys(root, vm.guest_mem + i), (void *)i); 832456fdf7SNico Boehr 842456fdf7SNico Boehr /* set up storage limit supression - leave mso and msl intact they are ignored anyways */ 852456fdf7SNico Boehr vm.sblk->cpuflags |= CPUSTAT_SM; 862456fdf7SNico Boehr 872456fdf7SNico Boehr /* set up the guest asce */ 882456fdf7SNico Boehr vm.save_area.guest.asce = __pa(guest_root) | ASCE_DT_REGION1 | REGION_TABLE_LENGTH; 892456fdf7SNico Boehr 902456fdf7SNico Boehr snippet_init(&vm, SNIPPET_NAME_START(c, sie_dat), 912456fdf7SNico Boehr SNIPPET_LEN(c, sie_dat), SNIPPET_UNPACK_OFF); 922456fdf7SNico Boehr } 932456fdf7SNico Boehr 942456fdf7SNico Boehr int main(void) 952456fdf7SNico Boehr { 962456fdf7SNico Boehr report_prefix_push("sie-dat"); 972456fdf7SNico Boehr if (!sclp_facilities.has_sief2) { 982456fdf7SNico Boehr report_skip("SIEF2 facility unavailable"); 992456fdf7SNico Boehr goto done; 1002456fdf7SNico Boehr } 1012456fdf7SNico Boehr 1022456fdf7SNico Boehr setup_guest(); 1032456fdf7SNico Boehr test_sie_dat(); 1042456fdf7SNico Boehr sie_guest_destroy(&vm); 1052456fdf7SNico Boehr 1062456fdf7SNico Boehr done: 1072456fdf7SNico Boehr report_prefix_pop(); 1082456fdf7SNico Boehr return report_summary(); 1092456fdf7SNico Boehr 1102456fdf7SNico Boehr } 111