@@ -97,4 +97,18 @@ static inline void low_prot_disable(void)
ctl_clear_bit(0, CTL0_LOW_ADDR_PROT);
}
+/**
+ * read_pgm_int_code - Get the program interruption code of the last pgm int
+ * on the current CPU.
+ *
+ * This is similar to clear_pgm_int(), except that it doesn't clear the
+ * interruption information from lowcore.
+ *
+ * Return: 0 when none occurred.
+ */
+static inline uint16_t read_pgm_int_code(void)
+{
+ return lowcore.pgm_int_code;
+}
+
#endif
@@ -8,6 +8,7 @@
#ifndef _ASMS390X_MEM_H_
#define _ASMS390X_MEM_H_
#include <asm/arch_def.h>
+#include <asm/facility.h>
/* create pointer while avoiding compiler warnings */
#define OPAQUE_PTR(x) ((void *)(((uint64_t)&lowcore) + (x)))
@@ -13,6 +13,7 @@
#include <libcflat.h>
#include <sie.h>
#include <asm/page.h>
+#include <asm/interrupt.h>
#include <libcflat.h>
#include <alloc_page.h>
#include <vmalloc.h>
@@ -56,6 +57,9 @@ void sie(struct vm *vm)
{
uint64_t old_cr13;
+ /* When a pgm int code is set, we'll never enter SIE below. */
+ assert(!read_pgm_int_code());
+
if (vm->sblk->sdf == 2)
memcpy(vm->sblk->pv_grregs, vm->save_area.guest.grs,
sizeof(vm->save_area.guest.grs));
@@ -81,7 +85,8 @@ void sie(struct vm *vm)
/* also handle all interruptions in home space while in SIE */
irq_set_dat_mode(true, AS_HOME);
- while (vm->sblk->icptcode == 0) {
+ /* leave SIE when we have an intercept or an interrupt so the test can react to it */
+ while (vm->sblk->icptcode == 0 && !read_pgm_int_code()) {
sie64a(vm->sblk, &vm->save_area);
sie_handle_validity(vm);
}