Message ID | 20231103092954.238491-8-nrb@linux.ibm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | s390x: Add support for running guests without MSO/MSL | expand |
On Fri, 3 Nov 2023 10:29:36 +0100 Nico Boehr <nrb@linux.ibm.com> wrote: > Since we now have the ability to run guests without MSO/MSL, add a test > to make sure this doesn't break. [...] > + /* the guest will now write to an unmapped address and we check that this causes a segment translation exception */ > + report_prefix_push("guest write to unmapped"); > + expect_pgm_int(); > + sie(&vm); > + check_pgm_int_code(PGM_INT_CODE_SEGMENT_TRANSLATION); can you also check that the faulting address is the one we expect? > + report_prefix_pop(); > +} > + [...] > diff --git a/s390x/snippets/c/sie-dat.c b/s390x/snippets/c/sie-dat.c > new file mode 100644 > index 000000000000..e07136bf7430 > --- /dev/null > +++ b/s390x/snippets/c/sie-dat.c > @@ -0,0 +1,52 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* > + * Snippet used by the sie-dat.c test to verify paging without MSO/MSL > + * > + * Copyright (c) 2023 IBM Corp > + * > + * Authors: > + * Nico Boehr <nrb@linux.ibm.com> > + */ > +#include <libcflat.h> > +#include <asm-generic/page.h> > +#include "sie-dat.h" > + > +static uint8_t test_page[GUEST_TEST_PAGE_COUNT * PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); I would call it test_pages [...]
On 11/3/23 10:29, Nico Boehr wrote: > Since we now have the ability to run guests without MSO/MSL, add a test > to make sure this doesn't break. > > Signed-off-by: Nico Boehr <nrb@linux.ibm.com> > Reviewed-by: Thomas Huth <thuth@redhat.com> Two small nits below > + > +static void test_sie_dat(void) > +{ > + uint64_t test_page_gpa, test_page_hpa; > + uint8_t *test_page_hva, expected_val; > + bool contents_match; > + uint8_t r1; > + > + /* guest will tell us the guest physical address of the test buffer */ > + sie(&vm); > + > + r1 = (vm.sblk->ipa & 0xf0) >> 4; > + test_page_gpa = vm.save_area.guest.grs[r1]; > + test_page_hpa = virt_to_pte_phys(guest_root, (void*)test_page_gpa); > + test_page_hva = __va(test_page_hpa); > + assert(vm.sblk->icptcode == ICPT_INST && > + (vm.sblk->ipa & 0xff00) == 0x8300 && vm.sblk->ipb == 0x9c0000); Move the assert right under the sie() call. > + report_info("test buffer gpa=0x%lx hva=%p", test_page_gpa, test_page_hva); > + > + /* guest will now write to the test buffer and we verify the contents */ > + sie(&vm); > + assert(vm.sblk->icptcode == ICPT_INST && > + vm.sblk->ipa == 0x8300 && vm.sblk->ipb == 0x440000); > + [...] > +static void setup_guest(void) > +{ > + extern const char SNIPPET_NAME_START(c, sie_dat)[]; > + extern const char SNIPPET_NAME_END(c, sie_dat)[]; > + uint64_t guest_max_addr; > + > + setup_vm(); > + snippet_setup_guest(&vm, false); > + > + /* allocate a region-1 table */ > + guest_root = pgd_alloc_one(); > + > + /* map guest memory 1:1 */ 0:guest_max_addr > + guest_max_addr = GUEST_TOTAL_PAGE_COUNT * PAGE_SIZE; > + for (uint64_t i = 0; i < guest_max_addr; i += PAGE_SIZE) > + install_page(guest_root, __pa(vm.guest_mem + i), (void *)i); > + > + /* set up storage limit supression - leave mso and msl intact they are ignored anyways */ > + vm.sblk->cpuflags |= CPUSTAT_SM; > + > + /* set up the guest asce */ > + vm.save_area.guest.asce = __pa(guest_root) | ASCE_DT_REGION1 | REGION_TABLE_LENGTH; > + > + snippet_init(&vm, SNIPPET_NAME_START(c, sie_dat), > + SNIPPET_LEN(c, sie_dat), SNIPPET_UNPACK_OFF); > +} > +
On Fri, Nov 03, 2023 at 10:29:36AM +0100, Nico Boehr wrote: > Since we now have the ability to run guests without MSO/MSL, add a test > to make sure this doesn't break. > > Signed-off-by: Nico Boehr <nrb@linux.ibm.com> > Reviewed-by: Thomas Huth <thuth@redhat.com> > --- > s390x/Makefile | 2 + > s390x/sie-dat.c | 110 +++++++++++++++++++++++++++++++++++++ > s390x/snippets/c/sie-dat.c | 52 ++++++++++++++++++ > s390x/snippets/c/sie-dat.h | 2 + > s390x/unittests.cfg | 3 + > 5 files changed, 169 insertions(+) > create mode 100644 s390x/sie-dat.c > create mode 100644 s390x/snippets/c/sie-dat.c > create mode 100644 s390x/snippets/c/sie-dat.h ... > +static uint8_t test_page[GUEST_TEST_PAGE_COUNT * PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); > + > +static inline void force_exit(void) > +{ > + asm volatile("diag 0,0,0x44\n"); > +} > + > +static inline void force_exit_value(uint64_t val) > +{ > + asm volatile( > + "diag %[val],0,0x9c\n" > + : : [val] "d"(val) > + ); > +} > + > +int main(void) > +{ > + uint8_t *invalid_ptr; > + > + memset(test_page, 0, sizeof(test_page)); > + /* tell the host the page's physical address (we're running DAT off) */ > + force_exit_value((uint64_t)test_page); > + > + /* write some value to the page so the host can verify it */ > + for (size_t i = 0; i < GUEST_TEST_PAGE_COUNT; i++) > + test_page[i * PAGE_SIZE] = 42 + i; > + > + /* indicate we've written all pages */ > + force_exit(); > + > + /* the first unmapped address */ > + invalid_ptr = (uint8_t *)(GUEST_TOTAL_PAGE_COUNT * PAGE_SIZE); > + *invalid_ptr = 42; > + > + /* indicate we've written the non-allowed page (should never get here) */ > + force_exit(); > + > + return 0; > +} The compiler will not necessarily generate the expected code here, since there is no data dependency between the used inline assemblies and the memory locations that are changed. That is: the compiler may move the inline assemblies and/or memory assignments around. In order to prevent that you could simply add a compiler barrier to both inline assemblies (add "memory" to the clobber list).
Quoting Janosch Frank (2023-11-03 15:16:36) [...] > > +static void setup_guest(void) > > +{ > > + extern const char SNIPPET_NAME_START(c, sie_dat)[]; > > + extern const char SNIPPET_NAME_END(c, sie_dat)[]; > > + uint64_t guest_max_addr; > > + > > + setup_vm(); > > + snippet_setup_guest(&vm, false); > > + > > + /* allocate a region-1 table */ > > + guest_root = pgd_alloc_one(); > > + > > + /* map guest memory 1:1 */ > > 0:guest_max_addr Sorry, I don't get what you mean.
diff --git a/s390x/Makefile b/s390x/Makefile index 947a4344738f..f79fd0098312 100644 --- a/s390x/Makefile +++ b/s390x/Makefile @@ -41,6 +41,7 @@ tests += $(TEST_DIR)/migration-sck.elf tests += $(TEST_DIR)/exittime.elf tests += $(TEST_DIR)/ex.elf tests += $(TEST_DIR)/topology.elf +tests += $(TEST_DIR)/sie-dat.elf pv-tests += $(TEST_DIR)/pv-diags.elf pv-tests += $(TEST_DIR)/pv-icptcode.elf @@ -123,6 +124,7 @@ snippet_lib = $(snippet_asmlib) lib/auxinfo.o # perquisites (=guests) for the snippet hosts. # $(TEST_DIR)/<snippet-host>.elf: snippets = $(SNIPPET_DIR)/<c/asm>/<snippet>.gbin $(TEST_DIR)/mvpg-sie.elf: snippets = $(SNIPPET_DIR)/c/mvpg-snippet.gbin +$(TEST_DIR)/sie-dat.elf: snippets = $(SNIPPET_DIR)/c/sie-dat.gbin $(TEST_DIR)/spec_ex-sie.elf: snippets = $(SNIPPET_DIR)/c/spec_ex.gbin $(TEST_DIR)/pv-diags.elf: pv-snippets += $(SNIPPET_DIR)/asm/pv-diag-yield.gbin diff --git a/s390x/sie-dat.c b/s390x/sie-dat.c new file mode 100644 index 000000000000..89e2c4c13db2 --- /dev/null +++ b/s390x/sie-dat.c @@ -0,0 +1,110 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Tests SIE with paging. + * + * Copyright 2023 IBM Corp. + * + * Authors: + * Nico Boehr <nrb@linux.ibm.com> + */ +#include <libcflat.h> +#include <vmalloc.h> +#include <asm/pgtable.h> +#include <mmu.h> +#include <asm/page.h> +#include <asm/interrupt.h> +#include <alloc_page.h> +#include <sclp.h> +#include <sie.h> +#include <snippet.h> +#include "snippets/c/sie-dat.h" + +static struct vm vm; +static pgd_t *guest_root; + +static void test_sie_dat(void) +{ + uint64_t test_page_gpa, test_page_hpa; + uint8_t *test_page_hva, expected_val; + bool contents_match; + uint8_t r1; + + /* guest will tell us the guest physical address of the test buffer */ + sie(&vm); + + r1 = (vm.sblk->ipa & 0xf0) >> 4; + test_page_gpa = vm.save_area.guest.grs[r1]; + test_page_hpa = virt_to_pte_phys(guest_root, (void*)test_page_gpa); + test_page_hva = __va(test_page_hpa); + assert(vm.sblk->icptcode == ICPT_INST && + (vm.sblk->ipa & 0xff00) == 0x8300 && vm.sblk->ipb == 0x9c0000); + report_info("test buffer gpa=0x%lx hva=%p", test_page_gpa, test_page_hva); + + /* guest will now write to the test buffer and we verify the contents */ + sie(&vm); + assert(vm.sblk->icptcode == ICPT_INST && + vm.sblk->ipa == 0x8300 && vm.sblk->ipb == 0x440000); + + contents_match = true; + for (unsigned int i = 0; i < GUEST_TEST_PAGE_COUNT; i++) { + expected_val = 42 + i; + if (test_page_hva[i * PAGE_SIZE] != expected_val) { + report_fail("page %u mismatch actual_val=%x expected_val=%x", + i, test_page_hva[i], expected_val); + contents_match = false; + } + } + report(contents_match, "test buffer contents match"); + + /* the guest will now write to an unmapped address and we check that this causes a segment translation exception */ + report_prefix_push("guest write to unmapped"); + expect_pgm_int(); + sie(&vm); + check_pgm_int_code(PGM_INT_CODE_SEGMENT_TRANSLATION); + report_prefix_pop(); +} + +static void setup_guest(void) +{ + extern const char SNIPPET_NAME_START(c, sie_dat)[]; + extern const char SNIPPET_NAME_END(c, sie_dat)[]; + uint64_t guest_max_addr; + + setup_vm(); + snippet_setup_guest(&vm, false); + + /* allocate a region-1 table */ + guest_root = pgd_alloc_one(); + + /* map guest memory 1:1 */ + guest_max_addr = GUEST_TOTAL_PAGE_COUNT * PAGE_SIZE; + for (uint64_t i = 0; i < guest_max_addr; i += PAGE_SIZE) + install_page(guest_root, __pa(vm.guest_mem + i), (void *)i); + + /* set up storage limit supression - leave mso and msl intact they are ignored anyways */ + vm.sblk->cpuflags |= CPUSTAT_SM; + + /* set up the guest asce */ + vm.save_area.guest.asce = __pa(guest_root) | ASCE_DT_REGION1 | REGION_TABLE_LENGTH; + + snippet_init(&vm, SNIPPET_NAME_START(c, sie_dat), + SNIPPET_LEN(c, sie_dat), SNIPPET_UNPACK_OFF); +} + +int main(void) +{ + report_prefix_push("sie-dat"); + if (!sclp_facilities.has_sief2) { + report_skip("SIEF2 facility unavailable"); + goto done; + } + + setup_guest(); + test_sie_dat(); + sie_guest_destroy(&vm); + +done: + report_prefix_pop(); + return report_summary(); + +} diff --git a/s390x/snippets/c/sie-dat.c b/s390x/snippets/c/sie-dat.c new file mode 100644 index 000000000000..e07136bf7430 --- /dev/null +++ b/s390x/snippets/c/sie-dat.c @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Snippet used by the sie-dat.c test to verify paging without MSO/MSL + * + * Copyright (c) 2023 IBM Corp + * + * Authors: + * Nico Boehr <nrb@linux.ibm.com> + */ +#include <libcflat.h> +#include <asm-generic/page.h> +#include "sie-dat.h" + +static uint8_t test_page[GUEST_TEST_PAGE_COUNT * PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); + +static inline void force_exit(void) +{ + asm volatile("diag 0,0,0x44\n"); +} + +static inline void force_exit_value(uint64_t val) +{ + asm volatile( + "diag %[val],0,0x9c\n" + : : [val] "d"(val) + ); +} + +int main(void) +{ + uint8_t *invalid_ptr; + + memset(test_page, 0, sizeof(test_page)); + /* tell the host the page's physical address (we're running DAT off) */ + force_exit_value((uint64_t)test_page); + + /* write some value to the page so the host can verify it */ + for (size_t i = 0; i < GUEST_TEST_PAGE_COUNT; i++) + test_page[i * PAGE_SIZE] = 42 + i; + + /* indicate we've written all pages */ + force_exit(); + + /* the first unmapped address */ + invalid_ptr = (uint8_t *)(GUEST_TOTAL_PAGE_COUNT * PAGE_SIZE); + *invalid_ptr = 42; + + /* indicate we've written the non-allowed page (should never get here) */ + force_exit(); + + return 0; +} diff --git a/s390x/snippets/c/sie-dat.h b/s390x/snippets/c/sie-dat.h new file mode 100644 index 000000000000..ed3f99f75f9c --- /dev/null +++ b/s390x/snippets/c/sie-dat.h @@ -0,0 +1,2 @@ +#define GUEST_TEST_PAGE_COUNT 10 +#define GUEST_TOTAL_PAGE_COUNT 256 diff --git a/s390x/unittests.cfg b/s390x/unittests.cfg index 68e119e4fcaa..184658ff7d8d 100644 --- a/s390x/unittests.cfg +++ b/s390x/unittests.cfg @@ -247,3 +247,6 @@ file = topology.elf [topology-2] file = topology.elf extra_params = -cpu max,ctop=on -smp sockets=31,cores=8,maxcpus=248 -append '-sockets 31 -cores 8' + +[sie-dat] +file = sie-dat.elf