diff mbox series

[kvm-unit-tests,v3,6/6] s390x: add a test for SIE without MSO/MSL

Message ID 20230601070202.152094-7-nrb@linux.ibm.com (mailing list archive)
State New, archived
Headers show
Series s390x: Add support for running guests without MSO/MSL | expand

Commit Message

Nico Boehr June 1, 2023, 7:02 a.m. UTC
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>
---
 s390x/Makefile             |   2 +
 s390x/sie-dat.c            | 120 +++++++++++++++++++++++++++++++++++++
 s390x/snippets/c/sie-dat.c |  58 ++++++++++++++++++
 s390x/unittests.cfg        |   3 +
 4 files changed, 183 insertions(+)
 create mode 100644 s390x/sie-dat.c
 create mode 100644 s390x/snippets/c/sie-dat.c

Comments

Janosch Frank June 5, 2023, 9:57 a.m. UTC | #1
On 6/1/23 09:02, 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>
> ---
>   s390x/Makefile             |   2 +
>   s390x/sie-dat.c            | 120 +++++++++++++++++++++++++++++++++++++
>   s390x/snippets/c/sie-dat.c |  58 ++++++++++++++++++
>   s390x/unittests.cfg        |   3 +
>   4 files changed, 183 insertions(+)
>   create mode 100644 s390x/sie-dat.c
>   create mode 100644 s390x/snippets/c/sie-dat.c
> 
> diff --git a/s390x/Makefile b/s390x/Makefile
> index a80db538810e..4921669ee4c3 100644
> --- a/s390x/Makefile
> +++ b/s390x/Makefile
> @@ -40,6 +40,7 @@ tests += $(TEST_DIR)/panic-loop-pgm.elf
>   tests += $(TEST_DIR)/migration-sck.elf
>   tests += $(TEST_DIR)/exittime.elf
>   tests += $(TEST_DIR)/ex.elf
> +tests += $(TEST_DIR)/sie-dat.elf
>   
>   pv-tests += $(TEST_DIR)/pv-diags.elf
>   
> @@ -120,6 +121,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/snippet-pv-diag-yield.gbin
> diff --git a/s390x/sie-dat.c b/s390x/sie-dat.c
> new file mode 100644
> index 000000000000..c490a2aa825c
> --- /dev/null
> +++ b/s390x/sie-dat.c
> @@ -0,0 +1,120 @@
> +/* 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/asm-offsets.h>

I only did a cursory glance and wasn't able to see a use for this include.

> +#include <asm-generic/barrier.h>
> +#include <asm/pgtable.h>
> +#include <mmu.h>
> +#include <asm/page.h>
> +#include <asm/facility.h>

The sclp.h include should be enough, no?
You're not using test_facility() as far as I can see.

> +#include <asm/interrupt.h>
> +#include <asm/mem.h>
> +#include <alloc_page.h>
> +#include <sclp.h> > +#include <sie.h>
> +#include <snippet.h>
> +
> +static struct vm vm;
> +static pgd_t *guest_root;
> +
> +/* keep in sync with TEST_PAGE_COUNT in s390x/snippets/c/sie-dat.c */
> +#define GUEST_TEST_PAGE_COUNT 10
> +
> +/* keep in sync with TOTAL_PAGE_COUNT in s390x/snippets/c/sie-dat.c */
> +#define GUEST_TOTAL_PAGE_COUNT 256
> +
> +static void test_sie_dat(void)
> +{
> +	uint8_t r1;
> +	bool contents_match;
> +	uint64_t test_page_gpa, test_page_hpa;
> +	uint8_t *test_page_hva;
> +
> +	/* 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);
> +	report(vm.sblk->icptcode == ICPT_INST &&
> +	       (vm.sblk->ipa & 0xFF00) == 0x8300 && vm.sblk->ipb == 0x9c0000,
> +	       "test buffer gpa=0x%lx hva=%p", test_page_gpa, test_page_hva);

You could rebase on my pv_icptdata.h patch.
Also the report string and boolean don't really relate to each other.

Not every exit needs to be a report.
Some should rather be asserts() or report_info()s.

> +
> +	/* guest will now write to the test buffer and we verify the contents */
> +	sie(&vm);
> +	report(vm.sblk->icptcode == ICPT_INST &&
> +	       vm.sblk->ipa == 0x8300 && vm.sblk->ipb == 0x440000,
> +	       "guest wrote to test buffer");

Yup pv_icptdata.h

> +
> +	contents_match = true;
> +	for (unsigned int i = 0; i < GUEST_TEST_PAGE_COUNT; i++) {
> +		uint8_t expected_val = 42 + i;

Just because you can doesn't mean that you have to.
At least leave a \n when declaring new variables...

> +		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();
> +}
> +

[...]

> +}
> diff --git a/s390x/snippets/c/sie-dat.c b/s390x/snippets/c/sie-dat.c
> new file mode 100644
> index 000000000000..e156d0c36c4c
> --- /dev/null
> +++ b/s390x/snippets/c/sie-dat.c
> @@ -0,0 +1,58 @@
> +/* 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 <stddef.h>
> +#include <inttypes.h>
> +#include <string.h>
> +#include <asm-generic/page.h>
> +
> +/* keep in sync with GUEST_TEST_PAGE_COUNT in s390x/sie-dat.c */
> +#define TEST_PAGE_COUNT 10
> +static uint8_t test_page[TEST_PAGE_COUNT * PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
> +
> +/* keep in sync with GUEST_TOTAL_PAGE_COUNT in s390x/sie-dat.c */
> +#define TOTAL_PAGE_COUNT 256
> +
> +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)
> +	);
> +}

It feels like these need to go into a snippet lib.

> +
> +__attribute__((section(".text"))) int main(void)

The attribute shouldn't be needed anymore.

> +{
> +	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 < TEST_PAGE_COUNT; i++)

Why is i a size_t type?

> +		test_page[i * PAGE_SIZE] = 42 + i;
> +
> +	/* indicate we've written all pages */
> +	force_exit();
> +
> +	/* the first unmapped address */
> +	invalid_ptr = (uint8_t *)(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/unittests.cfg b/s390x/unittests.cfg
> index b61faf0737c3..24cd27202a08 100644
> --- a/s390x/unittests.cfg
> +++ b/s390x/unittests.cfg
> @@ -218,3 +218,6 @@ extra_params = -append '--parallel'
>   
>   [execute]
>   file = ex.elf
> +
> +[sie-dat]
> +file = sie-dat.elf
Nico Boehr July 10, 2023, 2:29 p.m. UTC | #2
Quoting Janosch Frank (2023-06-05 11:57:58)
[...]
> > diff --git a/s390x/sie-dat.c b/s390x/sie-dat.c
> > new file mode 100644
> > index 000000000000..c490a2aa825c
[...]
> > +#include <libcflat.h>
> > +#include <vmalloc.h>
> > +#include <asm/asm-offsets.h>
> 
> I only did a cursory glance and wasn't able to see a use for this include.

Yep, thanks, I cleaned up the includes a bit.

[...]
> > +static void test_sie_dat(void)
> > +{
> > +     uint8_t r1;
> > +     bool contents_match;
> > +     uint64_t test_page_gpa, test_page_hpa;
> > +     uint8_t *test_page_hva;
> > +
> > +     /* 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);
> > +     report(vm.sblk->icptcode == ICPT_INST &&
> > +            (vm.sblk->ipa & 0xFF00) == 0x8300 && vm.sblk->ipb == 0x9c0000,
> > +            "test buffer gpa=0x%lx hva=%p", test_page_gpa, test_page_hva);
> 
> You could rebase on my pv_icptdata.h patch.
> Also the report string and boolean don't really relate to each other.

Which patch are we talking about? pv_icptdata_check_diag()?

Note that this is not a PV test, so I guess it's not applicable here?

> Not every exit needs to be a report.
> Some should rather be asserts() or report_info()s.

Yeah, I have made report()s where it doesn't make sense to continue assert()s

> > +     contents_match = true;
> > +     for (unsigned int i = 0; i < GUEST_TEST_PAGE_COUNT; i++) {
> > +             uint8_t expected_val = 42 + i;
> 
> Just because you can doesn't mean that you have to.
> At least leave a \n when declaring new variables...

I am a bit confused but I *guess* you wanted me to move the declaration of
expected_val to the beginning of the function?

[...]
> > diff --git a/s390x/snippets/c/sie-dat.c b/s390x/snippets/c/sie-dat.c
> > new file mode 100644
> > index 000000000000..e156d0c36c4c
> > --- /dev/null
> > +++ b/s390x/snippets/c/sie-dat.c
> > @@ -0,0 +1,58 @@
> > +/* 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 <stddef.h>
> > +#include <inttypes.h>
> > +#include <string.h>
> > +#include <asm-generic/page.h>
> > +
> > +/* keep in sync with GUEST_TEST_PAGE_COUNT in s390x/sie-dat.c */
> > +#define TEST_PAGE_COUNT 10
> > +static uint8_t test_page[TEST_PAGE_COUNT * PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
> > +
> > +/* keep in sync with GUEST_TOTAL_PAGE_COUNT in s390x/sie-dat.c */
> > +#define TOTAL_PAGE_COUNT 256
> > +
> > +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)
> > +     );
> > +}
> 
> It feels like these need to go into a snippet lib.

A bunch of other tests do similar things, so I'll write a TODO and tackle it in
a seperate series.

[...]
> > +
> > +__attribute__((section(".text"))) int main(void)
> 
> The attribute shouldn't be needed anymore.

OK, removed.

[...]
> > +{
> > +     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 < TEST_PAGE_COUNT; i++)
> 
> Why is i a size_t type?

Because it's a suitable unsigned type for use as an array index.

What should it be instead?
Janosch Frank July 10, 2023, 3:05 p.m. UTC | #3
On 7/10/23 16:29, Nico Boehr wrote:
> Quoting Janosch Frank (2023-06-05 11:57:58)
> [...]
>>> diff --git a/s390x/sie-dat.c b/s390x/sie-dat.c
>>> new file mode 100644
>>> index 000000000000..c490a2aa825c
> [...]
>>> +#include <libcflat.h>
>>> +#include <vmalloc.h>
>>> +#include <asm/asm-offsets.h>
>>
>> I only did a cursory glance and wasn't able to see a use for this include.
> 
> Yep, thanks, I cleaned up the includes a bit.
> 
> [...]
>>> +static void test_sie_dat(void)
>>> +{
>>> +     uint8_t r1;
>>> +     bool contents_match;
>>> +     uint64_t test_page_gpa, test_page_hpa;
>>> +     uint8_t *test_page_hva;
>>> +
>>> +     /* 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);
>>> +     report(vm.sblk->icptcode == ICPT_INST &&
>>> +            (vm.sblk->ipa & 0xFF00) == 0x8300 && vm.sblk->ipb == 0x9c0000,
>>> +            "test buffer gpa=0x%lx hva=%p", test_page_gpa, test_page_hva);
>>
>> You could rebase on my pv_icptdata.h patch.
>> Also the report string and boolean don't really relate to each other.
> 
> Which patch are we talking about? pv_icptdata_check_diag()?
> 
> Note that this is not a PV test, so I guess it's not applicable here?

Ah right, we could extend that but for one use this should be fine.
Let's see if there'll be more SIE tests that need this before building a 
a full intercept check lib.

Could you lower-case the 0xFF00 when you re-spin?

> 
>> Not every exit needs to be a report.
>> Some should rather be asserts() or report_info()s.
> 
> Yeah, I have made report()s where it doesn't make sense to continue assert()s
> 
>>> +     contents_match = true;
>>> +     for (unsigned int i = 0; i < GUEST_TEST_PAGE_COUNT; i++) {
>>> +             uint8_t expected_val = 42 + i;
>>
>> Just because you can doesn't mean that you have to.
>> At least leave a \n when declaring new variables...
> 
> I am a bit confused but I *guess* you wanted me to move the declaration of
> expected_val to the beginning of the function?
> 

Personally I'm not a big fan of declaring variables in the lower 
function body, they are way too easy to overlook.

I dimly remember there being a rule but when I used a few minutes to 
look for it I couldn't find it anymore. Hmmmm, maybe I'm getting old.

> [...]
>>> diff --git a/s390x/snippets/c/sie-dat.c b/s390x/snippets/c/sie-dat.c
>>> new file mode 100644
>>> index 000000000000..e156d0c36c4c
>>> --- /dev/null
>>> +++ b/s390x/snippets/c/sie-dat.c
>>> @@ -0,0 +1,58 @@
>>> +/* 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 <stddef.h>
>>> +#include <inttypes.h>
>>> +#include <string.h>
>>> +#include <asm-generic/page.h>
>>> +
>>> +/* keep in sync with GUEST_TEST_PAGE_COUNT in s390x/sie-dat.c */
>>> +#define TEST_PAGE_COUNT 10
>>> +static uint8_t test_page[TEST_PAGE_COUNT * PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
>>> +
>>> +/* keep in sync with GUEST_TOTAL_PAGE_COUNT in s390x/sie-dat.c */
>>> +#define TOTAL_PAGE_COUNT 256
>>> +
>>> +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)
>>> +     );
>>> +}
>>
>> It feels like these need to go into a snippet lib.
> 
> A bunch of other tests do similar things, so I'll write a TODO and tackle it in
> a seperate series.

Thanks :)

> 
> [...]
>>> +
>>> +__attribute__((section(".text"))) int main(void)
>>
>> The attribute shouldn't be needed anymore.
> 
> OK, removed.
> 
> [...]
>>> +{
>>> +     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 < TEST_PAGE_COUNT; i++)
>>
>> Why is i a size_t type?
> 
> Because it's a suitable unsigned type for use as an array index.
> 
> What should it be instead?

I would have used a standard uint type but to be fair this doesn't kill 
me either.
diff mbox series

Patch

diff --git a/s390x/Makefile b/s390x/Makefile
index a80db538810e..4921669ee4c3 100644
--- a/s390x/Makefile
+++ b/s390x/Makefile
@@ -40,6 +40,7 @@  tests += $(TEST_DIR)/panic-loop-pgm.elf
 tests += $(TEST_DIR)/migration-sck.elf
 tests += $(TEST_DIR)/exittime.elf
 tests += $(TEST_DIR)/ex.elf
+tests += $(TEST_DIR)/sie-dat.elf
 
 pv-tests += $(TEST_DIR)/pv-diags.elf
 
@@ -120,6 +121,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/snippet-pv-diag-yield.gbin
diff --git a/s390x/sie-dat.c b/s390x/sie-dat.c
new file mode 100644
index 000000000000..c490a2aa825c
--- /dev/null
+++ b/s390x/sie-dat.c
@@ -0,0 +1,120 @@ 
+/* 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/asm-offsets.h>
+#include <asm-generic/barrier.h>
+#include <asm/pgtable.h>
+#include <mmu.h>
+#include <asm/page.h>
+#include <asm/facility.h>
+#include <asm/interrupt.h>
+#include <asm/mem.h>
+#include <alloc_page.h>
+#include <sclp.h>
+#include <sie.h>
+#include <snippet.h>
+
+static struct vm vm;
+static pgd_t *guest_root;
+
+/* keep in sync with TEST_PAGE_COUNT in s390x/snippets/c/sie-dat.c */
+#define GUEST_TEST_PAGE_COUNT 10
+
+/* keep in sync with TOTAL_PAGE_COUNT in s390x/snippets/c/sie-dat.c */
+#define GUEST_TOTAL_PAGE_COUNT 256
+
+static void test_sie_dat(void)
+{
+	uint8_t r1;
+	bool contents_match;
+	uint64_t test_page_gpa, test_page_hpa;
+	uint8_t *test_page_hva;
+
+	/* 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);
+	report(vm.sblk->icptcode == ICPT_INST &&
+	       (vm.sblk->ipa & 0xFF00) == 0x8300 && vm.sblk->ipb == 0x9c0000,
+	       "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);
+	report(vm.sblk->icptcode == ICPT_INST &&
+	       vm.sblk->ipa == 0x8300 && vm.sblk->ipb == 0x440000,
+	       "guest wrote to test buffer");
+
+	contents_match = true;
+	for (unsigned int i = 0; i < GUEST_TEST_PAGE_COUNT; i++) {
+		uint8_t 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..e156d0c36c4c
--- /dev/null
+++ b/s390x/snippets/c/sie-dat.c
@@ -0,0 +1,58 @@ 
+/* 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 <stddef.h>
+#include <inttypes.h>
+#include <string.h>
+#include <asm-generic/page.h>
+
+/* keep in sync with GUEST_TEST_PAGE_COUNT in s390x/sie-dat.c */
+#define TEST_PAGE_COUNT 10
+static uint8_t test_page[TEST_PAGE_COUNT * PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
+
+/* keep in sync with GUEST_TOTAL_PAGE_COUNT in s390x/sie-dat.c */
+#define TOTAL_PAGE_COUNT 256
+
+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)
+	);
+}
+
+__attribute__((section(".text"))) 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 < 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 *)(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/unittests.cfg b/s390x/unittests.cfg
index b61faf0737c3..24cd27202a08 100644
--- a/s390x/unittests.cfg
+++ b/s390x/unittests.cfg
@@ -218,3 +218,6 @@  extra_params = -append '--parallel'
 
 [execute]
 file = ex.elf
+
+[sie-dat]
+file = sie-dat.elf