cp/guest: implement Machine Check interrupt issuing
[hvf.git] / cp / guest / run.c
blob7c9f92f27f6dc3bb7db4020e6c335ab439ce44a0
1 /*
2 * (C) Copyright 2007-2012 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
4 * This file is released under the GPLv2. See the COPYING file for more
5 * details.
6 */
8 #include <directory.h>
9 #include <sched.h>
10 #include <dat.h>
11 #include <vcpu.h>
12 #include <slab.h>
14 static void __do_psw_swap(struct virt_cpu *cpu, u8 *gpsa, u64 old, u64 new,
15 int len)
17 memcpy(gpsa + old, &cpu->sie_cb.gpsw, len);
18 memcpy(&cpu->sie_cb.gpsw, gpsa + new, len);
21 static int __mch_int(struct virt_sys *sys)
23 struct virt_cpu *cpu = sys->cpu;
24 struct mch_int_code *mch;
25 u64 cr14;
26 u64 phy;
27 int ret;
29 if (!cpu->sie_cb.gpsw.m)
30 return 0;
32 /* Channel-Report Pending? */
33 if (pending_circbuf(&sys->crws)) {
34 cr14 = cpu->sie_cb.gcr[14];
36 if (cr14 & BIT64(35)) {
37 con_printf(sys->con, "Time for MCH int...\n");
39 /* get the guest's first page (PSA) */
40 ret = virt2phy_current(0, &phy);
41 if (ret) {
42 con_printf(sys->con, "Failed to queue up MCH "
43 "interruption: %d (%s)\n", ret,
44 errstrings[-ret]);
45 cpu->state = GUEST_STOPPED;
47 return 0;
50 /* do the PSW swap */
51 if (VCPU_ZARCH(cpu))
52 __do_psw_swap(cpu, (void*) phy, 0x160, 0x1e0, 16);
53 else
54 __do_psw_swap(cpu, (void*) phy, 48, 112, 8);
56 mch = (struct mch_int_code*) (phy + 0xe8);
59 * The following bits seem to work for Hercules
60 * (00400F1D 403B0000)
62 memset(mch, 0, sizeof(struct mch_int_code));
63 mch->cp = 1; /* channel report pending */
64 mch->wp = 1;
65 mch->ms = 1;
66 mch->pm = 1;
67 mch->ia = 1;
68 mch->fp = 1;
69 mch->gr = 1;
70 mch->cr = 1;
71 mch->st = 1;
72 mch->ar = 1;
73 mch->pr = 1;
74 mch->fc = 1;
75 mch->ap = 1;
76 mch->ct = 1;
77 mch->cc = 1;
79 return 1;
83 return 0;
86 static int __io_int(struct virt_sys *sys)
88 struct virt_cpu *cpu = sys->cpu;
89 struct vio_int *ioint;
90 u64 cr6;
91 u64 phy;
92 int ret;
93 int i;
95 /* are I/O interrupts enabled? */
96 if (!cpu->sie_cb.gpsw.io)
97 return 0;
99 cr6 = cpu->sie_cb.gcr[6];
101 mutex_lock(&cpu->int_lock);
102 /* for each subclass, check that... */
103 for(i=0; i<8; i++) {
104 /* ...the subclass is enabled */
105 if (!(cr6 & (0x80000000 >> i)))
106 continue;
108 /* ...there are interrupts of that subclass */
109 if (list_empty(&cpu->int_io[i]))
110 continue;
112 /* there is an interruption that we can perform */
113 ioint = list_first_entry(&cpu->int_io[i], struct vio_int, list);
114 list_del(&ioint->list);
116 mutex_unlock(&cpu->int_lock);
118 con_printf(sys->con, "Time for I/O int... isc:%d "
119 "%08x.%08x.%08x\n", i, ioint->ssid,
120 ioint->param, ioint->intid);
122 /* get the guest's first page (PSA) */
123 ret = virt2phy_current(0, &phy);
124 if (ret) {
125 con_printf(sys->con, "Failed to queue up I/O "
126 "interruption: %d (%s)\n", ret,
127 errstrings[-ret]);
128 cpu->state = GUEST_STOPPED;
130 return 0;
133 /* do the PSW swap */
134 if (VCPU_ZARCH(cpu))
135 __do_psw_swap(cpu, (void*) phy, 0x170, 0x1f0, 16);
136 else
137 __do_psw_swap(cpu, (void*) phy, 56, 120, 8);
139 *((u32*) (phy + 184)) = ioint->ssid;
140 *((u32*) (phy + 188)) = ioint->param;
141 *((u32*) (phy + 192)) = ioint->intid;
143 free(ioint);
145 return 1;
148 mutex_unlock(&cpu->int_lock);
149 return 0;
152 void run_guest(struct virt_sys *sys)
154 struct psw *psw = &sys->cpu->sie_cb.gpsw;
155 u64 save_gpr[16];
157 if (__io_int(sys))
158 goto go;
160 if (__mch_int(sys))
161 goto go;
163 if (psw->w) {
164 if (!psw->io && !psw->ex && !psw->m) {
165 con_printf(sys->con, "ENTERED CP DUE TO DISABLED WAIT\n");
166 sys->cpu->state = GUEST_STOPPED;
167 return;
170 /* wait state */
171 schedule();
172 return;
176 FIXME("need to ->icptcode = 0;");
177 FIXME("load FPRs & FPCR");
180 * IMPORTANT: We MUST keep a valid stack address in R15. This way,
181 * if SIE gets interrupted via an interrupt in the host, the
182 * scheduler can still get to the struct task pointer on the stack
184 asm volatile(
185 /* save current regs */
186 " stmg 0,15,%0\n"
187 /* load the address of the guest state save area */
188 " lr 14,%1\n"
189 /* load the address of the reg save area */
190 " la 15,%0\n"
191 /* load guest's R0-R13 */
192 " lmg 0,13,%2(14)\n"
193 /* SIE */
194 " sie %3(14)\n"
195 /* save guest's R0-R13 */
196 " stmg 0,13,%2(14)\n"
197 /* restore all regs */
198 " lmg 0,15,0(15)\n"
200 : /* output */
201 "+m" (save_gpr)
202 : /* input */
203 "a" (sys->cpu),
204 "J" (offsetof(struct virt_cpu, regs.gpr)),
205 "J" (offsetof(struct virt_cpu, sie_cb))
206 : /* clobbered */
207 "memory"
210 FIXME("store FPRs & FPCR");
212 handle_interception(sys);