s390x/kvm: diag288 instruction interception and handling

Intercept the diag288 requests from kvm guests, and hand the
requested command to the diag288 watchdog device for further
handling.

Signed-off-by: Xu Wang <gesaint@linux.vnet.ibm.com>
Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
This commit is contained in:
Xu Wang 2015-06-11 13:55:26 +02:00 committed by Christian Borntraeger
parent 188f24c2c1
commit 8fc639af4b
3 changed files with 48 additions and 0 deletions

View file

@ -1100,6 +1100,7 @@ uint32_t set_cc_nz_f128(float128 v);
/* misc_helper.c */
#ifndef CONFIG_USER_ONLY
int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3);
void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3);
#endif
void program_interrupt(CPUS390XState *env, uint32_t code, int ilen);

View file

@ -98,6 +98,7 @@
#define PRIV_E3_MPCIFC 0xd0
#define PRIV_E3_STPCIFC 0xd4
#define DIAG_TIMEREVENT 0x288
#define DIAG_IPL 0x308
#define DIAG_KVM_HYPERCALL 0x500
#define DIAG_KVM_BREAKPOINT 0x501
@ -1267,6 +1268,20 @@ static int handle_hypercall(S390CPU *cpu, struct kvm_run *run)
return ret;
}
static void kvm_handle_diag_288(S390CPU *cpu, struct kvm_run *run)
{
uint64_t r1, r3;
int rc;
cpu_synchronize_state(CPU(cpu));
r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
r3 = run->s390_sieic.ipa & 0x000f;
rc = handle_diag_288(&cpu->env, r1, r3);
if (rc) {
enter_pgmcheck(cpu, PGM_SPECIFICATION);
}
}
static void kvm_handle_diag_308(S390CPU *cpu, struct kvm_run *run)
{
uint64_t r1, r3;
@ -1306,6 +1321,9 @@ static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb)
*/
func_code = decode_basedisp_rs(&cpu->env, ipb, NULL) & DIAG_KVM_CODE_MASK;
switch (func_code) {
case DIAG_TIMEREVENT:
kvm_handle_diag_288(cpu, run);
break;
case DIAG_IPL:
kvm_handle_diag_308(cpu, run);
break;

View file

@ -30,6 +30,7 @@
#include <linux/kvm.h>
#endif
#include "exec/cpu_ldst.h"
#include "hw/watchdog/wdt_diag288.h"
#if !defined(CONFIG_USER_ONLY)
#include "sysemu/cpus.h"
@ -153,6 +154,34 @@ static int load_normal_reset(S390CPU *cpu)
return 0;
}
int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
{
uint64_t func = env->regs[r1];
uint64_t timeout = env->regs[r1 + 1];
uint64_t action = env->regs[r3];
Object *obj;
DIAG288State *diag288;
DIAG288Class *diag288_class;
if (r1 % 2 || action != 0) {
return -1;
}
/* Timeout must be more than 15 seconds except for timer deletion */
if (func != WDT_DIAG288_CANCEL && timeout < 15) {
return -1;
}
obj = object_resolve_path_type("", TYPE_WDT_DIAG288, NULL);
if (!obj) {
return -1;
}
diag288 = DIAG288(obj);
diag288_class = DIAG288_GET_CLASS(diag288);
return diag288_class->handle_timer(diag288, func, timeout);
}
#define DIAG_308_RC_OK 0x0001
#define DIAG_308_RC_NO_CONF 0x0102
#define DIAG_308_RC_INVALID 0x0402