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:
parent
188f24c2c1
commit
8fc639af4b
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user