v3 -> v4: * pick up R-b's (thanks Claudio, Janosch, Nick) * move diag intercept functions into sie-icpt.[hc] expose some more functionality to avoid interpreting the diag text with bit operations * move snippet exit functions into snippet-exit.h, guest part in s390x/snippet/lib * add barrier before snippet exit * simplify test (host and guest), add skip message Add a test case that tests the interpretation of STFLE performed by a nested guest using a snippet. Also add some functionality to s390x lib, namely: * exit (optionally with return code) from snippet * add function for checking diag intercepts, replacing pv_icptdata_check_diag v2 -> v3: * pick up Ack (thanks Andrew) * minor cosmetic change to rand generator * add sie_is_pv function * extend sie_is_diag_icpt to support pv, replace pv_icptdata_check_diag v1 -> v2: * implement SHA-256 based PRNG * pick up R-b (thanks Claudio) * change snippet exit API and implementation (thanks Claudio) * add stfle-sie to unittests.cfg Nina Schoetterl-Glausch (6): s390x: lib: Remove double include s390x: Add sie_is_pv s390x: Add function for checking diagnose intercepts s390x: Add library functions for exiting from snippet s390x: Use library functions for snippet exit s390x: Add test for STFLE interpretive execution (format-0) s390x/Makefile | 7 +- lib/s390x/asm/arch_def.h | 13 +++ lib/s390x/asm/facility.h | 10 ++- lib/s390x/pv_icptdata.h | 42 --------- lib/s390x/sie-icpt.h | 39 +++++++++ lib/s390x/sie.h | 6 ++ lib/s390x/snippet-exit.h | 47 ++++++++++ lib/s390x/sie-icpt.c | 60 +++++++++++++ lib/s390x/sie.c | 5 +- s390x/snippets/lib/snippet-exit.h | 28 ++++++ s390x/pv-diags.c | 9 +- s390x/pv-icptcode.c | 12 +-- s390x/pv-ipl.c | 8 +- s390x/sie-dat.c | 12 +-- s390x/snippets/c/sie-dat.c | 19 +--- s390x/snippets/c/stfle.c | 29 +++++++ s390x/stfle-sie.c | 138 ++++++++++++++++++++++++++++++ s390x/unittests.cfg | 3 + 18 files changed, 399 insertions(+), 88 deletions(-) delete mode 100644 lib/s390x/pv_icptdata.h create mode 100644 lib/s390x/sie-icpt.h create mode 100644 lib/s390x/snippet-exit.h create mode 100644 lib/s390x/sie-icpt.c create mode 100644 s390x/snippets/lib/snippet-exit.h create mode 100644 s390x/snippets/c/stfle.c create mode 100644 s390x/stfle-sie.c Range-diff against v3: 1: baecabf2 < -: -------- lib: Add pseudo random functions 2: b30314eb ! 1: 74832900 s390x: lib: Remove double include @@ Commit message libcflat.h was included twice. Reviewed-by: Claudio Imbrenda <imbrenda@xxxxxxxxxxxxx> + Reviewed-by: Janosch Frank <frankja@xxxxxxxxxxxxx> Signed-off-by: Nina Schoetterl-Glausch <nsg@xxxxxxxxxxxxx> ## lib/s390x/sie.c ## 3: f2af539b ! 2: 973607d1 s390x: Add sie_is_pv @@ Commit message Add a function to check if a guest VM is currently running protected. + Reviewed-by: Claudio Imbrenda <imbrenda@xxxxxxxxxxxxx> + Reviewed-by: Janosch Frank <frankja@xxxxxxxxxxxxx> + Reviewed-by: Nicholas Piggin <npiggin@xxxxxxxxx> Signed-off-by: Nina Schoetterl-Glausch <nsg@xxxxxxxxxxxxx> ## lib/s390x/sie.h ## 4: c4331d19 ! 3: 56f16e10 s390x: Add function for checking diagnose intercepts @@ Commit message Signed-off-by: Nina Schoetterl-Glausch <nsg@xxxxxxxxxxxxx> + ## s390x/Makefile ## +@@ s390x/Makefile: cflatobjs += lib/s390x/css_lib.o + cflatobjs += lib/s390x/malloc_io.o + cflatobjs += lib/s390x/uv.o + cflatobjs += lib/s390x/sie.o ++cflatobjs += lib/s390x/sie-icpt.o + cflatobjs += lib/s390x/fault.o + + OBJDIRS += lib/s390x + ## lib/s390x/pv_icptdata.h (deleted) ## @@ -/* SPDX-License-Identifier: GPL-2.0-only */ @@ lib/s390x/pv_icptdata.h (deleted) -} -#endif - ## lib/s390x/sie.h ## -@@ lib/s390x/sie.h: static inline bool sie_is_pv(struct vm *vm) - return vm->sblk->sdf == 2; - } - + ## lib/s390x/sie-icpt.h (new) ## +@@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Functionality for SIE interception handling. ++ * ++ * Copyright IBM Corp. 2024 ++ */ ++ ++#ifndef _S390X_SIE_ICPT_H_ ++#define _S390X_SIE_ICPT_H_ ++ ++#include <libcflat.h> ++#include <sie.h> ++ ++struct diag_itext { ++ uint64_t opcode : 8; ++ uint64_t r_1 : 4; ++ uint64_t r_2 : 4; ++ uint64_t r_base : 4; ++ uint64_t displace : 12; ++ uint64_t zero : 16; ++ uint64_t : 16; ++}; ++ ++struct diag_itext sblk_ip_as_diag(struct kvm_s390_sie_block *sblk); ++ +/** + * sie_is_diag_icpt() - Check if intercept is due to diagnose instruction + * @vm: the guest + * @diag: the expected diagnose code + * + * Check that the intercept is due to diagnose @diag and valid. -+ * For protected virtualisation, check that the intercept data meets additional ++ * For protected virtualization, check that the intercept data meets additional + * constraints. + * + * Returns: true if intercept is due to a valid and has matching diagnose code + */ +bool sie_is_diag_icpt(struct vm *vm, unsigned int diag); - void sie_guest_sca_create(struct vm *vm); - void sie_guest_create(struct vm *vm, uint64_t guest_mem, uint64_t guest_mem_len); - void sie_guest_destroy(struct vm *vm); ++ ++#endif /* _S390X_SIE_ICPT_H_ */ - ## lib/s390x/sie.c ## -@@ lib/s390x/sie.c: void sie_check_validity(struct vm *vm, uint16_t vir_exp) - report(vir_exp == vir, "VALIDITY: %x", vir); - } - -+bool sie_is_diag_icpt(struct vm *vm, unsigned int diag) + ## lib/s390x/sie-icpt.c (new) ## +@@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Functionality for SIE interception handling. ++ * ++ * Copyright IBM Corp. 2024 ++ */ ++ ++#include <sie-icpt.h> ++ ++struct diag_itext sblk_ip_as_diag(struct kvm_s390_sie_block *sblk) +{ + union { + struct { -+ uint64_t : 16; + uint64_t ipa : 16; + uint64_t ipb : 32; ++ uint64_t : 16; + }; -+ struct { -+ uint64_t : 16; -+ uint64_t opcode : 8; -+ uint64_t r_1 : 4; -+ uint64_t r_2 : 4; -+ uint64_t r_base : 4; -+ uint64_t displace : 12; -+ uint64_t zero : 16; -+ }; -+ } instr = { .ipa = vm->sblk->ipa, .ipb = vm->sblk->ipb }; ++ struct diag_itext diag; ++ } instr = { .ipa = sblk->ipa, .ipb = sblk->ipb }; ++ ++ return instr.diag; ++} ++ ++bool sie_is_diag_icpt(struct vm *vm, unsigned int diag) ++{ ++ struct diag_itext instr = sblk_ip_as_diag(vm->sblk); + uint8_t icptcode; + uint64_t code; + @@ lib/s390x/sie.c: void sie_check_validity(struct vm *vm, uint16_t vir_exp) + break; + default: + /* If a new diag is introduced add it to the cases above! */ -+ assert_msg(false, "unknown diag"); ++ assert_msg(false, "unknown diag 0x%x", diag); + } + + if (sie_is_pv(vm)) { @@ lib/s390x/sie.c: void sie_check_validity(struct vm *vm, uint16_t vir_exp) + code = (code + instr.displace) & 0xffff; + return code == diag; +} -+ - void sie_handle_validity(struct vm *vm) - { - if (vm->sblk->icptcode != ICPT_VALIDITY) ## s390x/pv-diags.c ## @@ @@ s390x/pv-diags.c #include <libcflat.h> #include <snippet.h> -#include <pv_icptdata.h> ++#include <sie-icpt.h> #include <sie.h> #include <sclp.h> #include <asm/facility.h> @@ s390x/pv-icptcode.c #include <sclp.h> #include <snippet.h> -#include <pv_icptdata.h> ++#include <sie-icpt.h> #include <asm/facility.h> #include <asm/barrier.h> #include <asm/sigp.h> @@ s390x/pv-ipl.c #include <sclp.h> #include <snippet.h> -#include <pv_icptdata.h> ++#include <sie-icpt.h> #include <asm/facility.h> #include <asm/uv.h> 5: a3f92777 ! 4: 8cafb8da s390x: Add library functions for exiting from snippet @@ Commit message Signed-off-by: Nina Schoetterl-Glausch <nsg@xxxxxxxxxxxxx> ## s390x/Makefile ## -@@ s390x/Makefile: cflatobjs += lib/s390x/css_lib.o - cflatobjs += lib/s390x/malloc_io.o - cflatobjs += lib/s390x/uv.o - cflatobjs += lib/s390x/sie.o -+cflatobjs += lib/s390x/snippet-host.o - cflatobjs += lib/s390x/fault.o +@@ s390x/Makefile: test_cases: $(tests) + test_cases_binary: $(tests_binary) + test_cases_pv: $(tests_pv_binary) + +-INCLUDE_PATHS = $(SRCDIR)/lib $(SRCDIR)/lib/s390x $(SRCDIR)/s390x ++SNIPPET_INCLUDE := ++INCLUDE_PATHS = $(SNIPPET_INCLUDE) $(SRCDIR)/lib $(SRCDIR)/lib/s390x $(SRCDIR)/s390x + # Include generated header files (e.g. in case of out-of-source builds) + INCLUDE_PATHS += lib + CPPFLAGS = $(addprefix -I,$(INCLUDE_PATHS)) +@@ s390x/Makefile: endif + $(SNIPPET_DIR)/asm/%.o: $(SNIPPET_DIR)/asm/%.S $(asm-offsets) + $(CC) $(CFLAGS) -c -nostdlib -o $@ $< + ++$(SNIPPET_DIR)/c/%.o: SNIPPET_INCLUDE := $(SNIPPET_DIR)/lib + $(SNIPPET_DIR)/c/%.o: $(SNIPPET_DIR)/c/%.c $(asm-offsets) + $(CC) $(CFLAGS) -c -nostdlib -o $@ $< - OBJDIRS += lib/s390x ## lib/s390x/asm/arch_def.h ## @@ lib/s390x/asm/arch_def.h: static inline uint32_t get_prefix(void) @@ lib/s390x/asm/arch_def.h: static inline uint32_t get_prefix(void) + #endif - ## lib/s390x/snippet-guest.h (new) ## + ## lib/s390x/snippet-exit.h (new) ## @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* -+ * Snippet functionality for the guest. ++ * Functionality handling snippet exits + * -+ * Copyright IBM Corp. 2023 ++ * Copyright IBM Corp. 2024 + */ + -+#ifndef _S390X_SNIPPET_GUEST_H_ -+#define _S390X_SNIPPET_GUEST_H_ -+ -+#include <asm/arch_def.h> -+#include <asm/barrier.h> -+ -+static inline void force_exit(void) -+{ -+ diag44(); -+ mb(); /* allow host to modify guest memory */ -+} -+ -+static inline void force_exit_value(uint64_t val) -+{ -+ diag9c(val); -+ mb(); /* allow host to modify guest memory */ -+} -+ -+#endif /* _S390X_SNIPPET_GUEST_H_ */ - - ## lib/s390x/snippet.h => lib/s390x/snippet-host.h ## -@@ - /* SPDX-License-Identifier: GPL-2.0-only */ - /* -- * Snippet definitions -+ * Snippet functionality for the host. - * - * Copyright IBM Corp. 2021 - * Author: Janosch Frank <frankja@xxxxxxxxxxxxx> - */ - --#ifndef _S390X_SNIPPET_H_ --#define _S390X_SNIPPET_H_ -+#ifndef _S390X_SNIPPET_HOST_H_ -+#define _S390X_SNIPPET_HOST_H_ - - #include <sie.h> - #include <uv.h> -@@ lib/s390x/snippet-host.h: static inline void snippet_setup_guest(struct vm *vm, bool is_pv) - } - } - -+bool snippet_is_force_exit(struct vm *vm); -+bool snippet_is_force_exit_value(struct vm *vm); -+uint64_t snippet_get_force_exit_value(struct vm *vm); -+void snippet_check_force_exit_value(struct vm *vm, uint64_t exit_exp); - #endif - - ## lib/s390x/snippet-host.c (new) ## -@@ -+/* SPDX-License-Identifier: GPL-2.0-only */ -+/* -+ * Snippet functionality for the host. -+ * -+ * Copyright IBM Corp. 2023 -+ */ ++#ifndef _S390X_SNIPPET_EXIT_H_ ++#define _S390X_SNIPPET_EXIT_H_ + +#include <libcflat.h> -+#include <snippet-host.h> +#include <sie.h> ++#include <sie-icpt.h> + -+bool snippet_is_force_exit(struct vm *vm) ++static inline bool snippet_is_force_exit(struct vm *vm) +{ + return sie_is_diag_icpt(vm, 0x44); +} + -+bool snippet_is_force_exit_value(struct vm *vm) ++static inline bool snippet_is_force_exit_value(struct vm *vm) +{ + return sie_is_diag_icpt(vm, 0x9c); +} + -+uint64_t snippet_get_force_exit_value(struct vm *vm) ++static inline uint64_t snippet_get_force_exit_value(struct vm *vm) +{ + struct kvm_s390_sie_block *sblk = vm->sblk; + + assert(snippet_is_force_exit_value(vm)); + -+ return vm->save_area.guest.grs[(sblk->ipa & 0xf0) >> 4]; ++ return vm->save_area.guest.grs[sblk_ip_as_diag(sblk).r_1]; +} + -+void snippet_check_force_exit_value(struct vm *vm, uint64_t value_exp) ++static inline void snippet_check_force_exit_value(struct vm *vm, uint64_t value_exp) +{ + uint64_t value; + @@ lib/s390x/snippet-host.c (new) + report_fail("guest forced exit with value"); + } +} - - ## lib/s390x/uv.c ## -@@ - #include <asm/uv.h> - #include <uv.h> - #include <sie.h> --#include <snippet.h> -+#include <snippet-host.h> - - static struct uv_cb_qui uvcb_qui = { - .header.cmd = UVC_CMD_QUI, - - ## s390x/mvpg-sie.c ## -@@ - #include <alloc_page.h> - #include <sclp.h> - #include <sie.h> --#include <snippet.h> -+#include <snippet-host.h> - - static struct vm vm; - - - ## s390x/pv-diags.c ## -@@ - * Janosch Frank <frankja@xxxxxxxxxxxxx> - */ - #include <libcflat.h> --#include <snippet.h> -+#include <snippet-host.h> - #include <sie.h> - #include <sclp.h> - #include <asm/facility.h> - - ## s390x/pv-icptcode.c ## -@@ - #include <sie.h> - #include <smp.h> - #include <sclp.h> --#include <snippet.h> -+#include <snippet-host.h> - #include <asm/facility.h> - #include <asm/barrier.h> - #include <asm/sigp.h> - - ## s390x/pv-ipl.c ## -@@ - #include <libcflat.h> - #include <sie.h> - #include <sclp.h> --#include <snippet.h> -+#include <snippet-host.h> - #include <asm/facility.h> - #include <asm/uv.h> - - - ## s390x/sie-dat.c ## -@@ - #include <alloc_page.h> - #include <sclp.h> - #include <sie.h> --#include <snippet.h> -+#include <snippet-host.h> - #include "snippets/c/sie-dat.h" - - static struct vm vm; - - ## s390x/spec_ex-sie.c ## -@@ - #include <asm/arch_def.h> - #include <alloc_page.h> - #include <sie.h> --#include <snippet.h> -+#include <snippet-host.h> - #include <hardware.h> - - static struct vm vm; - - ## s390x/uv-host.c ## -@@ - #include <sclp.h> - #include <smp.h> - #include <uv.h> --#include <snippet.h> -+#include <snippet-host.h> - #include <mmu.h> - #include <asm/page.h> - #include <asm/pgtable.h> ++ ++#endif /* _S390X_SNIPPET_EXIT_H_ */ + + ## s390x/snippets/lib/snippet-exit.h (new) ## +@@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Functionality for exiting the snippet. ++ * ++ * Copyright IBM Corp. 2023 ++ */ ++ ++#ifndef _S390X_SNIPPET_LIB_EXIT_H_ ++#define _S390X_SNIPPET_LIB_EXIT_H_ ++ ++#include <asm/arch_def.h> ++#include <asm/barrier.h> ++ ++static inline void force_exit(void) ++{ ++ mb(); /* host may read any memory written by the guest before */ ++ diag44(); ++ mb(); /* allow host to modify guest memory */ ++} ++ ++static inline void force_exit_value(uint64_t val) ++{ ++ mb(); /* host may read any memory written by the guest before */ ++ diag9c(val); ++ mb(); /* allow host to modify guest memory */ ++} ++ ++#endif /* _S390X_SNIPPET_LIB_EXIT_H_ */ 6: a1db588b ! 5: cd79e654 s390x: Use library functions for snippet exit @@ Commit message Replace the existing code for exiting from snippets with the newly introduced library functionality. + Reviewed-by: Claudio Imbrenda <imbrenda@xxxxxxxxxxxxx> + Reviewed-by: Nicholas Piggin <npiggin@xxxxxxxxx> Signed-off-by: Nina Schoetterl-Glausch <nsg@xxxxxxxxxxxxx> ## s390x/sie-dat.c ## +@@ + #include <sclp.h> + #include <sie.h> + #include <snippet.h> ++#include <snippet-exit.h> + #include "snippets/c/sie-dat.h" + + static struct vm vm; @@ s390x/sie-dat.c: static void test_sie_dat(void) uint64_t test_page_gpa, test_page_hpa; uint8_t *test_page_hva, expected_val; @@ s390x/snippets/c/sie-dat.c #include <libcflat.h> #include <asm-generic/page.h> #include <asm/mem.h> -+#include <snippet-guest.h> ++#include <snippet-exit.h> #include "sie-dat.h" static uint8_t test_pages[GUEST_TEST_PAGE_COUNT * PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); 7: 0b89b3c6 ! 6: 1e9893b6 s390x: Add test for STFLE interpretive execution (format-0) @@ s390x/snippets/c/stfle.c (new) + * Snippet used by the STLFE interpretive execution facilities test. + */ +#include <libcflat.h> -+#include <snippet-guest.h> ++#include <snippet-exit.h> + +int main(void) +{ + const unsigned int max_fac_len = 8; ++ uint64_t len_arg = max_fac_len - 1; + uint64_t res[max_fac_len + 1]; ++ uint64_t fac[max_fac_len]; + -+ res[0] = max_fac_len - 1; -+ asm volatile ( "lg 0,%[len]\n" ++ asm volatile ( "lgr 0,%[len]\n" + " stfle %[fac]\n" -+ " stg 0,%[len]\n" -+ : [fac] "=QS"(*(uint64_t(*)[max_fac_len])&res[1]), -+ [len] "+RT"(res[0]) ++ " lgr %[len],0\n" ++ : [fac] "=Q"(fac), ++ [len] "+d"(len_arg) + : + : "%r0", "cc" + ); ++ res[0] = len_arg; ++ memcpy(&res[1], fac, sizeof(fac)); + force_exit_value((uint64_t)&res); + return 0; +} @@ s390x/stfle-sie.c (new) +#include <stdlib.h> +#include <asm/facility.h> +#include <asm/time.h> -+#include <snippet-host.h> ++#include <snippet.h> ++#include <snippet-exit.h> +#include <alloc_page.h> +#include <sclp.h> +#include <rand.h> @@ s390x/stfle-sie.c (new) + +struct guest_stfle_res { + uint16_t len; -+ uint64_t reg; + unsigned char *mem; +}; + @@ s390x/stfle-sie.c (new) +{ + struct guest_stfle_res res; + uint64_t guest_stfle_addr; ++ uint64_t reg; + + sie(&vm); + assert(snippet_is_force_exit_value(&vm)); + guest_stfle_addr = snippet_get_force_exit_value(&vm); + res.mem = &vm.guest_mem[guest_stfle_addr]; -+ memcpy(&res.reg, res.mem, sizeof(res.reg)); -+ res.len = (res.reg & 0xff) + 1; -+ res.mem += sizeof(res.reg); ++ memcpy(®, res.mem, sizeof(reg)); ++ res.len = (reg & 0xff) + 1; ++ res.mem += sizeof(reg); + return res; +} + @@ s390x/stfle-sie.c (new) +int main(int argc, char **argv) +{ + struct args args = parse_args(argc, argv); ++ bool run_format_0 = test_facility(7); + + if (!sclp_facilities.has_sief2) { + report_skip("SIEF2 facility unavailable"); + goto out; + } ++ if (!run_format_0) ++ report_skip("STFLE facility not available"); + + report_info("PRNG seed: 0x%lx", args.seed); + prng_s = prng_init(args.seed); + setup_guest(); -+ if (test_facility(7)) ++ if (run_format_0) + test_stfle_format_0(); +out: + return report_summary(); base-commit: f246b16099478a916eab37b9bd1eb07c743a67d5 -- 2.44.0