forked from Minki/linux
KVM: s390: Create ioctl for Getting/Setting guest storage keys
Provide the KVM_S390_GET_SKEYS and KVM_S390_SET_SKEYS ioctl which can be used to get/set guest storage keys. This functionality is needed for live migration of s390 guests that use storage keys. Signed-off-by: Jason J. Herne <jjherne@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
e44fc8c9da
commit
30ee2a984f
@ -2762,6 +2762,64 @@ register number to be used.
|
|||||||
The "reserved" field is meant for future extensions. It is not used by
|
The "reserved" field is meant for future extensions. It is not used by
|
||||||
KVM with the currently defined set of flags.
|
KVM with the currently defined set of flags.
|
||||||
|
|
||||||
|
4.90 KVM_S390_GET_SKEYS
|
||||||
|
|
||||||
|
Capability: KVM_CAP_S390_SKEYS
|
||||||
|
Architectures: s390
|
||||||
|
Type: vm ioctl
|
||||||
|
Parameters: struct kvm_s390_skeys
|
||||||
|
Returns: 0 on success, KVM_S390_GET_KEYS_NONE if guest is not using storage
|
||||||
|
keys, negative value on error
|
||||||
|
|
||||||
|
This ioctl is used to get guest storage key values on the s390
|
||||||
|
architecture. The ioctl takes parameters via the kvm_s390_skeys struct.
|
||||||
|
|
||||||
|
struct kvm_s390_skeys {
|
||||||
|
__u64 start_gfn;
|
||||||
|
__u64 count;
|
||||||
|
__u64 skeydata_addr;
|
||||||
|
__u32 flags;
|
||||||
|
__u32 reserved[9];
|
||||||
|
};
|
||||||
|
|
||||||
|
The start_gfn field is the number of the first guest frame whose storage keys
|
||||||
|
you want to get.
|
||||||
|
|
||||||
|
The count field is the number of consecutive frames (starting from start_gfn)
|
||||||
|
whose storage keys to get. The count field must be at least 1 and the maximum
|
||||||
|
allowed value is defined as KVM_S390_SKEYS_ALLOC_MAX. Values outside this range
|
||||||
|
will cause the ioctl to return -EINVAL.
|
||||||
|
|
||||||
|
The skeydata_addr field is the address to a buffer large enough to hold count
|
||||||
|
bytes. This buffer will be filled with storage key data by the ioctl.
|
||||||
|
|
||||||
|
4.91 KVM_S390_SET_SKEYS
|
||||||
|
|
||||||
|
Capability: KVM_CAP_S390_SKEYS
|
||||||
|
Architectures: s390
|
||||||
|
Type: vm ioctl
|
||||||
|
Parameters: struct kvm_s390_skeys
|
||||||
|
Returns: 0 on success, negative value on error
|
||||||
|
|
||||||
|
This ioctl is used to set guest storage key values on the s390
|
||||||
|
architecture. The ioctl takes parameters via the kvm_s390_skeys struct.
|
||||||
|
See section on KVM_S390_GET_SKEYS for struct definition.
|
||||||
|
|
||||||
|
The start_gfn field is the number of the first guest frame whose storage keys
|
||||||
|
you want to set.
|
||||||
|
|
||||||
|
The count field is the number of consecutive frames (starting from start_gfn)
|
||||||
|
whose storage keys to get. The count field must be at least 1 and the maximum
|
||||||
|
allowed value is defined as KVM_S390_SKEYS_ALLOC_MAX. Values outside this range
|
||||||
|
will cause the ioctl to return -EINVAL.
|
||||||
|
|
||||||
|
The skeydata_addr field is the address to a buffer containing count bytes of
|
||||||
|
storage keys. Each byte in the buffer will be set as the storage key for a
|
||||||
|
single frame starting at start_gfn for count frames.
|
||||||
|
|
||||||
|
Note: If any architecturally invalid key value is found in the given data then
|
||||||
|
the ioctl will return -EINVAL.
|
||||||
|
|
||||||
5. The kvm_run structure
|
5. The kvm_run structure
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
|
@ -179,6 +179,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
|||||||
case KVM_CAP_MP_STATE:
|
case KVM_CAP_MP_STATE:
|
||||||
case KVM_CAP_S390_USER_SIGP:
|
case KVM_CAP_S390_USER_SIGP:
|
||||||
case KVM_CAP_S390_USER_STSI:
|
case KVM_CAP_S390_USER_STSI:
|
||||||
|
case KVM_CAP_S390_SKEYS:
|
||||||
r = 1;
|
r = 1;
|
||||||
break;
|
break;
|
||||||
case KVM_CAP_S390_MEM_OP:
|
case KVM_CAP_S390_MEM_OP:
|
||||||
@ -729,6 +730,108 @@ static int kvm_s390_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static long kvm_s390_get_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)
|
||||||
|
{
|
||||||
|
uint8_t *keys;
|
||||||
|
uint64_t hva;
|
||||||
|
unsigned long curkey;
|
||||||
|
int i, r = 0;
|
||||||
|
|
||||||
|
if (args->flags != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* Is this guest using storage keys? */
|
||||||
|
if (!mm_use_skey(current->mm))
|
||||||
|
return KVM_S390_GET_SKEYS_NONE;
|
||||||
|
|
||||||
|
/* Enforce sane limit on memory allocation */
|
||||||
|
if (args->count < 1 || args->count > KVM_S390_SKEYS_MAX)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
keys = kmalloc_array(args->count, sizeof(uint8_t),
|
||||||
|
GFP_KERNEL | __GFP_NOWARN);
|
||||||
|
if (!keys)
|
||||||
|
keys = vmalloc(sizeof(uint8_t) * args->count);
|
||||||
|
if (!keys)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
for (i = 0; i < args->count; i++) {
|
||||||
|
hva = gfn_to_hva(kvm, args->start_gfn + i);
|
||||||
|
if (kvm_is_error_hva(hva)) {
|
||||||
|
r = -EFAULT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
curkey = get_guest_storage_key(current->mm, hva);
|
||||||
|
if (IS_ERR_VALUE(curkey)) {
|
||||||
|
r = curkey;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
keys[i] = curkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = copy_to_user((uint8_t __user *)args->skeydata_addr, keys,
|
||||||
|
sizeof(uint8_t) * args->count);
|
||||||
|
if (r)
|
||||||
|
r = -EFAULT;
|
||||||
|
out:
|
||||||
|
kvfree(keys);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long kvm_s390_set_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)
|
||||||
|
{
|
||||||
|
uint8_t *keys;
|
||||||
|
uint64_t hva;
|
||||||
|
int i, r = 0;
|
||||||
|
|
||||||
|
if (args->flags != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* Enforce sane limit on memory allocation */
|
||||||
|
if (args->count < 1 || args->count > KVM_S390_SKEYS_MAX)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
keys = kmalloc_array(args->count, sizeof(uint8_t),
|
||||||
|
GFP_KERNEL | __GFP_NOWARN);
|
||||||
|
if (!keys)
|
||||||
|
keys = vmalloc(sizeof(uint8_t) * args->count);
|
||||||
|
if (!keys)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
r = copy_from_user(keys, (uint8_t __user *)args->skeydata_addr,
|
||||||
|
sizeof(uint8_t) * args->count);
|
||||||
|
if (r) {
|
||||||
|
r = -EFAULT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable storage key handling for the guest */
|
||||||
|
s390_enable_skey();
|
||||||
|
|
||||||
|
for (i = 0; i < args->count; i++) {
|
||||||
|
hva = gfn_to_hva(kvm, args->start_gfn + i);
|
||||||
|
if (kvm_is_error_hva(hva)) {
|
||||||
|
r = -EFAULT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lowest order bit is reserved */
|
||||||
|
if (keys[i] & 0x01) {
|
||||||
|
r = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = set_guest_storage_key(current->mm, hva,
|
||||||
|
(unsigned long)keys[i], 0);
|
||||||
|
if (r)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
kvfree(keys);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
long kvm_arch_vm_ioctl(struct file *filp,
|
long kvm_arch_vm_ioctl(struct file *filp,
|
||||||
unsigned int ioctl, unsigned long arg)
|
unsigned int ioctl, unsigned long arg)
|
||||||
{
|
{
|
||||||
@ -788,6 +891,26 @@ long kvm_arch_vm_ioctl(struct file *filp,
|
|||||||
r = kvm_s390_vm_has_attr(kvm, &attr);
|
r = kvm_s390_vm_has_attr(kvm, &attr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case KVM_S390_GET_SKEYS: {
|
||||||
|
struct kvm_s390_skeys args;
|
||||||
|
|
||||||
|
r = -EFAULT;
|
||||||
|
if (copy_from_user(&args, argp,
|
||||||
|
sizeof(struct kvm_s390_skeys)))
|
||||||
|
break;
|
||||||
|
r = kvm_s390_get_skeys(kvm, &args);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case KVM_S390_SET_SKEYS: {
|
||||||
|
struct kvm_s390_skeys args;
|
||||||
|
|
||||||
|
r = -EFAULT;
|
||||||
|
if (copy_from_user(&args, argp,
|
||||||
|
sizeof(struct kvm_s390_skeys)))
|
||||||
|
break;
|
||||||
|
r = kvm_s390_set_skeys(kvm, &args);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
r = -ENOTTY;
|
r = -ENOTTY;
|
||||||
}
|
}
|
||||||
|
@ -147,6 +147,16 @@ struct kvm_pit_config {
|
|||||||
|
|
||||||
#define KVM_PIT_SPEAKER_DUMMY 1
|
#define KVM_PIT_SPEAKER_DUMMY 1
|
||||||
|
|
||||||
|
struct kvm_s390_skeys {
|
||||||
|
__u64 start_gfn;
|
||||||
|
__u64 count;
|
||||||
|
__u64 skeydata_addr;
|
||||||
|
__u32 flags;
|
||||||
|
__u32 reserved[9];
|
||||||
|
};
|
||||||
|
#define KVM_S390_GET_SKEYS_NONE 1
|
||||||
|
#define KVM_S390_SKEYS_MAX 1048576
|
||||||
|
|
||||||
#define KVM_EXIT_UNKNOWN 0
|
#define KVM_EXIT_UNKNOWN 0
|
||||||
#define KVM_EXIT_EXCEPTION 1
|
#define KVM_EXIT_EXCEPTION 1
|
||||||
#define KVM_EXIT_IO 2
|
#define KVM_EXIT_IO 2
|
||||||
@ -791,6 +801,7 @@ struct kvm_ppc_smmu_info {
|
|||||||
#define KVM_CAP_S390_VECTOR_REGISTERS 107
|
#define KVM_CAP_S390_VECTOR_REGISTERS 107
|
||||||
#define KVM_CAP_S390_MEM_OP 108
|
#define KVM_CAP_S390_MEM_OP 108
|
||||||
#define KVM_CAP_S390_USER_STSI 109
|
#define KVM_CAP_S390_USER_STSI 109
|
||||||
|
#define KVM_CAP_S390_SKEYS 110
|
||||||
|
|
||||||
#ifdef KVM_CAP_IRQ_ROUTING
|
#ifdef KVM_CAP_IRQ_ROUTING
|
||||||
|
|
||||||
@ -1168,6 +1179,9 @@ struct kvm_s390_ucas_mapping {
|
|||||||
#define KVM_GET_REG_LIST _IOWR(KVMIO, 0xb0, struct kvm_reg_list)
|
#define KVM_GET_REG_LIST _IOWR(KVMIO, 0xb0, struct kvm_reg_list)
|
||||||
/* Available with KVM_CAP_S390_MEM_OP */
|
/* Available with KVM_CAP_S390_MEM_OP */
|
||||||
#define KVM_S390_MEM_OP _IOW(KVMIO, 0xb1, struct kvm_s390_mem_op)
|
#define KVM_S390_MEM_OP _IOW(KVMIO, 0xb1, struct kvm_s390_mem_op)
|
||||||
|
/* Available with KVM_CAP_S390_SKEYS */
|
||||||
|
#define KVM_S390_GET_SKEYS _IOW(KVMIO, 0xb2, struct kvm_s390_skeys)
|
||||||
|
#define KVM_S390_SET_SKEYS _IOW(KVMIO, 0xb3, struct kvm_s390_skeys)
|
||||||
|
|
||||||
#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
|
#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
|
||||||
#define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1)
|
#define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1)
|
||||||
|
Loading…
Reference in New Issue
Block a user