changeset 654:57988d03241d

cp/guest: implement Machine Check interrupt issuing Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
date Thu, 29 Mar 2012 17:44:13 -0400
parents 0d289341e756
children 10df8e1a7d69
files cp/guest/run.c
diffstat 1 files changed, 69 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/cp/guest/run.c	Thu Mar 29 17:42:13 2012 -0400
+++ b/cp/guest/run.c	Thu Mar 29 17:44:13 2012 -0400
@@ -1,5 +1,5 @@
 /*
- * (C) Copyright 2007-2011  Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
+ * (C) Copyright 2007-2012  Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
  *
  * This file is released under the GPLv2.  See the COPYING file for more
  * details.
@@ -18,6 +18,71 @@
 	memcpy(&cpu->sie_cb.gpsw, gpsa + new, len);
 }
 
+static int __mch_int(struct virt_sys *sys)
+{
+	struct virt_cpu *cpu = sys->cpu;
+	struct mch_int_code *mch;
+	u64 cr14;
+	u64 phy;
+	int ret;
+
+	if (!cpu->sie_cb.gpsw.m)
+		return 0;
+
+	/* Channel-Report Pending? */
+	if (pending_circbuf(&sys->crws)) {
+		cr14 = cpu->sie_cb.gcr[14];
+
+		if (cr14 & BIT64(35)) {
+			con_printf(sys->con, "Time for MCH int...\n");
+
+			/* get the guest's first page (PSA) */
+			ret = virt2phy_current(0, &phy);
+			if (ret) {
+				con_printf(sys->con, "Failed to queue up MCH "
+					   "interruption: %d (%s)\n", ret,
+					   errstrings[-ret]);
+				cpu->state = GUEST_STOPPED;
+
+				return 0;
+			}
+
+			/* do the PSW swap */
+			if (VCPU_ZARCH(cpu))
+				__do_psw_swap(cpu, (void*) phy, 0x160, 0x1e0, 16);
+			else
+				__do_psw_swap(cpu, (void*) phy, 48, 112, 8);
+
+			mch = (struct mch_int_code*) (phy + 0xe8);
+
+			/*
+			 * The following bits seem to work for Hercules
+			 * (00400F1D 403B0000)
+			 */
+			memset(mch, 0, sizeof(struct mch_int_code));
+			mch->cp = 1; /* channel report pending */
+			mch->wp = 1;
+			mch->ms = 1;
+			mch->pm = 1;
+			mch->ia = 1;
+			mch->fp = 1;
+			mch->gr = 1;
+			mch->cr = 1;
+			mch->st = 1;
+			mch->ar = 1;
+			mch->pr = 1;
+			mch->fc = 1;
+			mch->ap = 1;
+			mch->ct = 1;
+			mch->cc = 1;
+
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
 static int __io_int(struct virt_sys *sys)
 {
 	struct virt_cpu *cpu = sys->cpu;
@@ -92,6 +157,9 @@
 	if (__io_int(sys))
 		goto go;
 
+	if (__mch_int(sys))
+		goto go;
+
 	if (psw->w) {
 		if (!psw->io && !psw->ex && !psw->m) {
 			con_printf(sys->con, "ENTERED CP DUE TO DISABLED WAIT\n");