mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-23 19:49:43 +00:00
s390x/kvm: enable guarded storage
Introduce guarded storage support for KVM guests on s390. We need to enable the capability, extend machine check validity, sigp store-additional-status-at-address, and migration. The feature is fenced for older machine type versions. Signed-off-by: Fan Zhang <zhangfan@linux.vnet.ibm.com> Reviewed-by: Cornelia Huck <cohuck@redhat.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
This commit is contained in:
parent
c0a9cd940e
commit
62deb62d99
@ -211,6 +211,7 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
|
|||||||
s390mc->ri_allowed = true;
|
s390mc->ri_allowed = true;
|
||||||
s390mc->cpu_model_allowed = true;
|
s390mc->cpu_model_allowed = true;
|
||||||
s390mc->css_migration_enabled = true;
|
s390mc->css_migration_enabled = true;
|
||||||
|
s390mc->gs_allowed = true;
|
||||||
mc->init = ccw_init;
|
mc->init = ccw_init;
|
||||||
mc->reset = s390_machine_reset;
|
mc->reset = s390_machine_reset;
|
||||||
mc->hot_add_cpu = s390_hot_add_cpu;
|
mc->hot_add_cpu = s390_hot_add_cpu;
|
||||||
@ -288,6 +289,22 @@ bool cpu_model_allowed(void)
|
|||||||
return get_machine_class()->cpu_model_allowed;
|
return get_machine_class()->cpu_model_allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool gs_allowed(void)
|
||||||
|
{
|
||||||
|
if (kvm_enabled()) {
|
||||||
|
MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
|
||||||
|
if (object_class_dynamic_cast(OBJECT_CLASS(mc),
|
||||||
|
TYPE_S390_CCW_MACHINE)) {
|
||||||
|
S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
|
||||||
|
|
||||||
|
return s390mc->gs_allowed;
|
||||||
|
}
|
||||||
|
/* Make sure the "none" machine can have gs */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static char *machine_get_loadparm(Object *obj, Error **errp)
|
static char *machine_get_loadparm(Object *obj, Error **errp)
|
||||||
{
|
{
|
||||||
S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
|
S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
|
||||||
@ -515,6 +532,7 @@ static void ccw_machine_2_9_class_options(MachineClass *mc)
|
|||||||
{
|
{
|
||||||
S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
|
S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
|
||||||
|
|
||||||
|
s390mc->gs_allowed = false;
|
||||||
ccw_machine_2_10_class_options(mc);
|
ccw_machine_2_10_class_options(mc);
|
||||||
SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_9);
|
SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_9);
|
||||||
s390mc->css_migration_enabled = false;
|
s390mc->css_migration_enabled = false;
|
||||||
|
@ -40,12 +40,15 @@ typedef struct S390CcwMachineClass {
|
|||||||
bool ri_allowed;
|
bool ri_allowed;
|
||||||
bool cpu_model_allowed;
|
bool cpu_model_allowed;
|
||||||
bool css_migration_enabled;
|
bool css_migration_enabled;
|
||||||
|
bool gs_allowed;
|
||||||
} S390CcwMachineClass;
|
} S390CcwMachineClass;
|
||||||
|
|
||||||
/* runtime-instrumentation allowed by the machine */
|
/* runtime-instrumentation allowed by the machine */
|
||||||
bool ri_allowed(void);
|
bool ri_allowed(void);
|
||||||
/* cpu model allowed by the machine */
|
/* cpu model allowed by the machine */
|
||||||
bool cpu_model_allowed(void);
|
bool cpu_model_allowed(void);
|
||||||
|
/* guarded-storage allowed by the machine */
|
||||||
|
bool gs_allowed(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if (vmstate based) migration of the channel subsystem
|
* Returns true if (vmstate based) migration of the channel subsystem
|
||||||
|
@ -89,6 +89,7 @@ typedef struct CPUS390XState {
|
|||||||
CPU_DoubleU vregs[32][2]; /* vector registers */
|
CPU_DoubleU vregs[32][2]; /* vector registers */
|
||||||
uint32_t aregs[16]; /* access registers */
|
uint32_t aregs[16]; /* access registers */
|
||||||
uint8_t riccb[64]; /* runtime instrumentation control */
|
uint8_t riccb[64]; /* runtime instrumentation control */
|
||||||
|
uint64_t gscb[4]; /* guarded storage control */
|
||||||
|
|
||||||
/* Fields up to this point are not cleared by initial CPU reset */
|
/* Fields up to this point are not cleared by initial CPU reset */
|
||||||
struct {} start_initial_reset_fields;
|
struct {} start_initial_reset_fields;
|
||||||
@ -1166,6 +1167,7 @@ int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, uint64_t *hw_limit);
|
|||||||
void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu);
|
void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu);
|
||||||
int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu);
|
int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu);
|
||||||
int kvm_s390_get_ri(void);
|
int kvm_s390_get_ri(void);
|
||||||
|
int kvm_s390_get_gs(void);
|
||||||
void kvm_s390_crypto_reset(void);
|
void kvm_s390_crypto_reset(void);
|
||||||
#else
|
#else
|
||||||
static inline void kvm_s390_io_interrupt(uint16_t subchannel_id,
|
static inline void kvm_s390_io_interrupt(uint16_t subchannel_id,
|
||||||
@ -1220,6 +1222,10 @@ static inline int kvm_s390_get_ri(void)
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
static inline int kvm_s390_get_gs(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
static inline void kvm_s390_crypto_reset(void)
|
static inline void kvm_s390_crypto_reset(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -1328,6 +1334,7 @@ static inline bool s390_get_squash_mcss(void)
|
|||||||
#define MCIC_VB_CR 0x0000000400000000ULL
|
#define MCIC_VB_CR 0x0000000400000000ULL
|
||||||
#define MCIC_VB_ST 0x0000000100000000ULL
|
#define MCIC_VB_ST 0x0000000100000000ULL
|
||||||
#define MCIC_VB_AR 0x0000000040000000ULL
|
#define MCIC_VB_AR 0x0000000040000000ULL
|
||||||
|
#define MCIC_VB_GS 0x0000000008000000ULL
|
||||||
#define MCIC_VB_PR 0x0000000000200000ULL
|
#define MCIC_VB_PR 0x0000000000200000ULL
|
||||||
#define MCIC_VB_FC 0x0000000000100000ULL
|
#define MCIC_VB_FC 0x0000000000100000ULL
|
||||||
#define MCIC_VB_CT 0x0000000000020000ULL
|
#define MCIC_VB_CT 0x0000000000020000ULL
|
||||||
|
@ -139,6 +139,7 @@ static int cap_async_pf;
|
|||||||
static int cap_mem_op;
|
static int cap_mem_op;
|
||||||
static int cap_s390_irq;
|
static int cap_s390_irq;
|
||||||
static int cap_ri;
|
static int cap_ri;
|
||||||
|
static int cap_gs;
|
||||||
|
|
||||||
static int active_cmma;
|
static int active_cmma;
|
||||||
|
|
||||||
@ -301,6 +302,11 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
|
|||||||
cap_ri = 1;
|
cap_ri = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (gs_allowed()) {
|
||||||
|
if (kvm_vm_enable_cap(s, KVM_CAP_S390_GS, 0) == 0) {
|
||||||
|
cap_gs = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Try to enable AIS facility */
|
/* Try to enable AIS facility */
|
||||||
kvm_vm_enable_cap(s, KVM_CAP_S390_AIS, 0);
|
kvm_vm_enable_cap(s, KVM_CAP_S390_AIS, 0);
|
||||||
@ -472,6 +478,11 @@ int kvm_arch_put_registers(CPUState *cs, int level)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (can_sync_regs(cs, KVM_SYNC_GSCB)) {
|
||||||
|
memcpy(cs->kvm_run->s.regs.gscb, env->gscb, 32);
|
||||||
|
cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_GSCB;
|
||||||
|
}
|
||||||
|
|
||||||
/* Finally the prefix */
|
/* Finally the prefix */
|
||||||
if (can_sync_regs(cs, KVM_SYNC_PREFIX)) {
|
if (can_sync_regs(cs, KVM_SYNC_PREFIX)) {
|
||||||
cs->kvm_run->s.regs.prefix = env->psa;
|
cs->kvm_run->s.regs.prefix = env->psa;
|
||||||
@ -578,6 +589,10 @@ int kvm_arch_get_registers(CPUState *cs)
|
|||||||
memcpy(env->riccb, cs->kvm_run->s.regs.riccb, 64);
|
memcpy(env->riccb, cs->kvm_run->s.regs.riccb, 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (can_sync_regs(cs, KVM_SYNC_GSCB)) {
|
||||||
|
memcpy(env->gscb, cs->kvm_run->s.regs.gscb, 32);
|
||||||
|
}
|
||||||
|
|
||||||
/* pfault parameters */
|
/* pfault parameters */
|
||||||
if (can_sync_regs(cs, KVM_SYNC_PFAULT)) {
|
if (can_sync_regs(cs, KVM_SYNC_PFAULT)) {
|
||||||
env->pfault_token = cs->kvm_run->s.regs.pft;
|
env->pfault_token = cs->kvm_run->s.regs.pft;
|
||||||
@ -1474,22 +1489,28 @@ static void sigp_stop(CPUState *cs, run_on_cpu_data arg)
|
|||||||
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
|
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ADTL_SAVE_AREA_SIZE 1024
|
#define ADTL_GS_OFFSET 1024 /* offset of GS data in adtl save area */
|
||||||
static int kvm_s390_store_adtl_status(S390CPU *cpu, hwaddr addr)
|
#define ADTL_GS_MIN_SIZE 2048 /* minimal size of adtl save area for GS */
|
||||||
|
static int do_store_adtl_status(S390CPU *cpu, hwaddr addr, hwaddr len)
|
||||||
{
|
{
|
||||||
|
hwaddr save = len;
|
||||||
void *mem;
|
void *mem;
|
||||||
hwaddr len = ADTL_SAVE_AREA_SIZE;
|
|
||||||
|
|
||||||
mem = cpu_physical_memory_map(addr, &len, 1);
|
mem = cpu_physical_memory_map(addr, &save, 1);
|
||||||
if (!mem) {
|
if (!mem) {
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
if (len != ADTL_SAVE_AREA_SIZE) {
|
if (save != len) {
|
||||||
cpu_physical_memory_unmap(mem, len, 1, 0);
|
cpu_physical_memory_unmap(mem, len, 1, 0);
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(mem, &cpu->env.vregs, 512);
|
if (s390_has_feat(S390_FEAT_VECTOR)) {
|
||||||
|
memcpy(mem, &cpu->env.vregs, 512);
|
||||||
|
}
|
||||||
|
if (s390_has_feat(S390_FEAT_GUARDED_STORAGE) && len >= ADTL_GS_MIN_SIZE) {
|
||||||
|
memcpy(mem + ADTL_GS_OFFSET, &cpu->env.gscb, 32);
|
||||||
|
}
|
||||||
|
|
||||||
cpu_physical_memory_unmap(mem, len, 1, len);
|
cpu_physical_memory_unmap(mem, len, 1, len);
|
||||||
|
|
||||||
@ -1585,12 +1606,17 @@ static void sigp_store_status_at_address(CPUState *cs, run_on_cpu_data arg)
|
|||||||
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
|
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ADTL_SAVE_LC_MASK 0xfUL
|
||||||
static void sigp_store_adtl_status(CPUState *cs, run_on_cpu_data arg)
|
static void sigp_store_adtl_status(CPUState *cs, run_on_cpu_data arg)
|
||||||
{
|
{
|
||||||
S390CPU *cpu = S390_CPU(cs);
|
S390CPU *cpu = S390_CPU(cs);
|
||||||
SigpInfo *si = arg.host_ptr;
|
SigpInfo *si = arg.host_ptr;
|
||||||
|
uint8_t lc = si->param & ADTL_SAVE_LC_MASK;
|
||||||
|
hwaddr addr = si->param & ~ADTL_SAVE_LC_MASK;
|
||||||
|
hwaddr len = 1UL << (lc ? lc : 10);
|
||||||
|
|
||||||
if (!s390_has_feat(S390_FEAT_VECTOR)) {
|
if (!s390_has_feat(S390_FEAT_VECTOR) &&
|
||||||
|
!s390_has_feat(S390_FEAT_GUARDED_STORAGE)) {
|
||||||
set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
|
set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1601,15 +1627,32 @@ static void sigp_store_adtl_status(CPUState *cs, run_on_cpu_data arg)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parameter must be aligned to 1024-byte boundary */
|
/* address must be aligned to length */
|
||||||
if (si->param & 0x3ff) {
|
if (addr & (len - 1)) {
|
||||||
|
set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no GS: only lc == 0 is valid */
|
||||||
|
if (!s390_has_feat(S390_FEAT_GUARDED_STORAGE) &&
|
||||||
|
lc != 0) {
|
||||||
|
set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GS: 0, 10, 11, 12 are valid */
|
||||||
|
if (s390_has_feat(S390_FEAT_GUARDED_STORAGE) &&
|
||||||
|
lc != 0 &&
|
||||||
|
lc != 10 &&
|
||||||
|
lc != 11 &&
|
||||||
|
lc != 12) {
|
||||||
set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
|
set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu_synchronize_state(cs);
|
cpu_synchronize_state(cs);
|
||||||
|
|
||||||
if (kvm_s390_store_adtl_status(cpu, si->param)) {
|
if (do_store_adtl_status(cpu, addr, len)) {
|
||||||
set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
|
set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2188,6 +2231,9 @@ static uint64_t build_channel_report_mcic(void)
|
|||||||
if (s390_has_feat(S390_FEAT_VECTOR)) {
|
if (s390_has_feat(S390_FEAT_VECTOR)) {
|
||||||
mcic |= MCIC_VB_VR;
|
mcic |= MCIC_VB_VR;
|
||||||
}
|
}
|
||||||
|
if (s390_has_feat(S390_FEAT_GUARDED_STORAGE)) {
|
||||||
|
mcic |= MCIC_VB_GS;
|
||||||
|
}
|
||||||
return mcic;
|
return mcic;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2253,6 +2299,11 @@ int kvm_s390_get_ri(void)
|
|||||||
return cap_ri;
|
return cap_ri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int kvm_s390_get_gs(void)
|
||||||
|
{
|
||||||
|
return cap_gs;
|
||||||
|
}
|
||||||
|
|
||||||
int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state)
|
int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state)
|
||||||
{
|
{
|
||||||
struct kvm_mp_state mp_state = {};
|
struct kvm_mp_state mp_state = {};
|
||||||
|
@ -174,6 +174,22 @@ const VMStateDescription vmstate_exval = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool gscb_needed(void *opaque)
|
||||||
|
{
|
||||||
|
return kvm_s390_get_gs();
|
||||||
|
}
|
||||||
|
|
||||||
|
const VMStateDescription vmstate_gscb = {
|
||||||
|
.name = "cpu/gscb",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.needed = gscb_needed,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_UINT64_ARRAY(env.gscb, S390CPU, 4),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const VMStateDescription vmstate_s390_cpu = {
|
const VMStateDescription vmstate_s390_cpu = {
|
||||||
.name = "cpu",
|
.name = "cpu",
|
||||||
.post_load = cpu_post_load,
|
.post_load = cpu_post_load,
|
||||||
@ -207,6 +223,7 @@ const VMStateDescription vmstate_s390_cpu = {
|
|||||||
&vmstate_vregs,
|
&vmstate_vregs,
|
||||||
&vmstate_riccb,
|
&vmstate_riccb,
|
||||||
&vmstate_exval,
|
&vmstate_exval,
|
||||||
|
&vmstate_gscb,
|
||||||
NULL
|
NULL
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user