diff --git a/.gitignore b/.gitignore
index 784cb2ddbcb8..1fa5c0c0ea76 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
 *.o
 *.flat
 *.elf
+*.img
 .pc
 patches
 .stgit-*
diff --git a/configure b/configure
index 5d2cd90cd180..29191f4b0994 100755
--- a/configure
+++ b/configure
@@ -18,6 +18,7 @@ u32_long=
 vmm="qemu"
 errata_force=0
 erratatxt="errata.txt"
+host_key_document=
 
 usage() {
     cat <<-EOF
@@ -40,6 +41,8 @@ usage() {
 	                           no environ is provided by the user (enabled by default)
 	    --erratatxt=FILE       specify a file to use instead of errata.txt. Use
 	                           '--erratatxt=' to ensure no file is used.
+	    --host-key-document=HOST_KEY_DOCUMENT
+	                           host-key-document to use (s390x only)
 EOF
     exit 1
 }
@@ -91,6 +94,9 @@ while [[ "$1" = -* ]]; do
 	--erratatxt)
 	    erratatxt="$arg"
 	    ;;
+	--host-key-document)
+	    host_key_document="$arg"
+	    ;;
 	--help)
 	    usage
 	    ;;
@@ -207,6 +213,8 @@ PRETTY_PRINT_STACKS=$pretty_print_stacks
 ENVIRON_DEFAULT=$environ_default
 ERRATATXT=$erratatxt
 U32_LONG_FMT=$u32_long
+GENPROTIMG=genprotimg
+HOST_KEY_DOCUMENT=$host_key_document
 EOF
 
 cat <<EOF > lib/config.h
diff --git a/s390x/Makefile b/s390x/Makefile
index ddb4b48ecbf9..a57655dcce10 100644
--- a/s390x/Makefile
+++ b/s390x/Makefile
@@ -17,12 +17,19 @@ tests += $(TEST_DIR)/stsi.elf
 tests += $(TEST_DIR)/skrf.elf
 tests += $(TEST_DIR)/smp.elf
 tests += $(TEST_DIR)/sclp.elf
-tests_binary = $(patsubst %.elf,%.bin,$(tests))
 
-all: directories test_cases test_cases_binary
+tests_binary = $(patsubst %.elf,%.bin,$(tests))
+ifneq ($(HOST_KEY_DOCUMENT),)
+tests_pv_img = $(patsubst %.elf,%.pv.img,$(tests))
+else
+tests_pv_img =
+endif
+
+all: directories test_cases test_cases_binary test_cases_pv
 
 test_cases: $(tests)
 test_cases_binary: $(tests_binary)
+test_cases_pv: $(tests_pv_img)
 
 CFLAGS += -std=gnu99
 CFLAGS += -ffreestanding
@@ -68,8 +75,11 @@ FLATLIBS = $(libcflat)
 %.bin: %.elf
 	$(OBJCOPY) -O binary  $< $@
 
+%.pv.img: %.bin $(HOST_KEY_DOCUMENT)
+	$(GENPROTIMG) --host-key-document $(HOST_KEY_DOCUMENT) --no-verify --image $< -o $@
+
 arch_clean: asm_offsets_clean
-	$(RM) $(TEST_DIR)/*.{o,elf,bin} $(TEST_DIR)/.*.d lib/s390x/.*.d
+	$(RM) $(TEST_DIR)/*.{o,elf,bin,img} $(TEST_DIR)/.*.d lib/s390x/.*.d
 
 generated-files = $(asm-offsets)
 $(tests:.elf=.o) $(cstart.o) $(cflatobjs): $(generated-files)
diff --git a/s390x/unittests.cfg b/s390x/unittests.cfg
index b307329354f6..6beaca45fb20 100644
--- a/s390x/unittests.cfg
+++ b/s390x/unittests.cfg
@@ -16,6 +16,8 @@
 #			 # a test. The check line can contain multiple files
 #			 # to check separated by a space but each check
 #			 # parameter needs to be of the form <path>=<value>
+# pv_support = 0|1       # Optionally specify whether a test supports the
+#                        # execution as a PV guest.
 ##############################################################################
 
 [selftest-setup]
@@ -25,62 +27,80 @@ extra_params = -append 'test 123'
 
 [intercept]
 file = intercept.elf
+pv_support = 1
 
 [emulator]
 file = emulator.elf
+pv_support = 1
 
 [sieve]
 file = sieve.elf
 groups = selftest
 # can take fairly long when KVM is nested inside z/VM
 timeout = 600
+pv_support = 1
 
 [sthyi]
 file = sthyi.elf
+pv_support = 1
 
 [skey]
 file = skey.elf
+pv_support = 1
 
 [diag10]
 file = diag10.elf
+pv_support = 1
 
 [diag308]
 file = diag308.elf
+pv_support = 1
 
 [pfmf]
 file = pfmf.elf
+pv_support = 1
 
 [cmm]
 file = cmm.elf
+pv_support = 1
 
 [vector]
 file = vector.elf
+pv_support = 1
 
 [gs]
 file = gs.elf
+pv_support = 1
 
 [iep]
 file = iep.elf
+pv_support = 1
 
 [cpumodel]
 file = cpumodel.elf
+pv_support = 1
 
 [diag288]
 file = diag288.elf
 extra_params=-device diag288,id=watchdog0 --watchdog-action inject-nmi
+pv_support = 1
 
 [stsi]
 file = stsi.elf
 extra_params=-name kvm-unit-test --uuid 0fb84a86-727c-11ea-bc55-0242ac130003 -smp 1,maxcpus=8
+pv_support = 1
 
 [smp]
 file = smp.elf
 smp = 2
+pv_support = 1
 
 [sclp-1g]
 file = sclp.elf
 extra_params = -m 1G
+pv_support = 1
 
 [sclp-3g]
 file = sclp.elf
 extra_params = -m 3G
+pv_support = 1
diff --git a/scripts/common.bash b/scripts/common.bash
index 9a6ebbd7f287..971d0661287c 100644
--- a/scripts/common.bash
+++ b/scripts/common.bash
@@ -1,3 +1,20 @@
+function pv_cmd ()
+{
+	local cmd=$1
+	local testname=$2
+	local groups=$3
+	local smp=$4
+	local kernel=$5
+	local opts=$6
+	local arch=$7
+	local check=$8
+	local accel=$9
+	local timeout=${10}
+
+	kernel=${kernel%.elf}.pv.img
+	# do not run the PV test cases by default
+	"$cmd" "${testname}_PV" "$groups pv nodefault" "$smp" "$kernel" "$opts" "$arch" "$check" "$accel" "$timeout"
+}
 
 function for_each_unittest()
 {
@@ -12,12 +29,16 @@ function for_each_unittest()
 	local check
 	local accel
 	local timeout
+	local pv_support
 
 	exec {fd}<"$unittests"
 
 	while read -r -u $fd line; do
 		if [[ "$line" =~ ^\[(.*)\]$ ]]; then
-			"$cmd" "$testname" "$groups" "$smp" "$kernel" "$opts" "$arch" "$check" "$accel" "$timeout"
+			if [ "${pv_support}" == 1 ]; then
+				pv_cmd "$cmd" "$testname" "$groups" "$smp" "$kernel" "$opts" "$arch" "$check" "$accel" "$timeout"
+			fi
+
 			testname=${BASH_REMATCH[1]}
 			smp=1
 			kernel=""
@@ -27,6 +48,7 @@ function for_each_unittest()
 			check=""
 			accel=""
 			timeout=""
+			pv_support=""
 		elif [[ $line =~ ^file\ *=\ *(.*)$ ]]; then
 			kernel=$TEST_DIR/${BASH_REMATCH[1]}
 		elif [[ $line =~ ^smp\ *=\ *(.*)$ ]]; then
@@ -43,8 +65,14 @@ function for_each_unittest()
 			accel=${BASH_REMATCH[1]}
 		elif [[ $line =~ ^timeout\ *=\ *(.*)$ ]]; then
 			timeout=${BASH_REMATCH[1]}
+		elif [[ $line =~ ^pv_support\ *=\ *(.*)$ ]]; then
+			pv_support=${BASH_REMATCH[1]}
 		fi
 	done
+
 	"$cmd" "$testname" "$groups" "$smp" "$kernel" "$opts" "$arch" "$check" "$accel" "$timeout"
+	if [ "${pv_support}" == 1 ]; then
+		pv_cmd "$cmd" "$testname" "$groups" "$smp" "$kernel" "$opts" "$arch" "$check" "$accel" "$timeout"
+	fi
 	exec {fd}<&-
 }
